From 9324a7776da8b2d2210b76a88330c3f695d9b9f6 Mon Sep 17 00:00:00 2001 From: MuniSakkuru Date: Wed, 15 Dec 2021 17:49:48 +0000 Subject: [PATCH] Version 4.0.0 Alexa Auto SDK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Alexa Auto SDK is for automotive OEMs to integrate Alexa directly into vehicles. **v4.0.0** * v4.0.0 released on 2021-12-15 **Enhancements** * Deprecated the C++ and Java platform interfaces in favor of an asynchronous message-based API. Auto SDK client applications use the new `MessageBroker` to publish and subscribe to Alexa Auto Services Bridge (AASB) messages. The C++ sample app is refactored to use the new API to provide a reference implementation for Linux platforms. The Alexa Auto Client Service (AACS) sample app provides the reference implementation for Android platforms. See the [Auto SDK Migration Guide](./MIGRATION.md) for help migrating your application to use the new API. * Enhanced the Auto SDK build system with the Conan package manager. The new build system introduces modular builds, better dependency management, and simpler build artifacts. The Auto SDK build system includes the Auto SDK Builder Tool script, which wraps the Conan build commands with a simple interface similar to the previous version of Auto SDK Builder. See the [Build Alexa Auto SDK documentation](./BUILDING.md) for details about the build system and the [Migration Guide](./MIGRATION.md) for help migrating your build to the new version of Builder Tool. * Extended the features of Alexa Presentation Language (APL) support for automotive. The `APL` module provides messages to report vehicle properties such as the display theme, driving state, and ambient light conditions. The property settings affect how APL documents render on screen; for example, some APL content is automatically hidden when the vehicle starts moving, and the display contrast updates with the day or night mode setting. Auto SDK 4.0 supports APL 1.9. For more information about the Auto SDK `APL` interface, see the [APL module documentation.](./modules/apl/README.md) * Added the `CustomDomain` interface, which establishes a bidirectional communication channel between your Auto SDK client application and your custom cloud skill. `CustomDomain` includes messages for exchanging directives, events, and context between the vehicle and your skill, achieving a fully customizable experience. For more information about the Auto SDK `CustomDomain` interface, See the [Custom Domain module documentation.](./modules/custom-domain/README.md) * Added the `MediaPlaybackRequestor` interface, which enables Alexa to play the user’s favorite media content as soon as they start their vehicle. `MediaPlaybackRequestor` simplifies content selection for the user by removing the need for the user to use buttons or voice commands to resume the Alexa media content that was playing when they stopped the vehicle. For more information about the Auto SDK `MediaPlaybackRequestor` interface, See the [Alexa module documentation.](./modules/alexa/README.md) * Extended the `AudioOutput` interface and added configuration to allow ducking Alexa media. Your application can use this feature for enhanced control of Alexa content audio focus according to your platform requirements. For more information about audio ducking, see the [Core module documentation.](./modules/core/README.md) * Updated the Auto SDK to use AVS Device SDK Version 1.25.0. For information about this version of AVS Device SDK, see the [AVS Device SDK release notes.](https://developer.amazon.com/en-US/docs/alexa/avs-device-sdk/release-notes.html#version-1250) * Added LVC support for Alexa Custom Assistant specialized handoffs. You can configure the default fallback and self-introduction prompts for your custom assistant while offline. For more information, see the `Alexa Custom Assistant` extension documentation. * Integrated the Auto SDK Conan build system enhancements to AACS and the AACS sample app. You can use a single Gradle command to build AACS and the AACS sample app. For build instructions, see the [AACS documentation.](./aacs/android/README.md) * Added the following enhancements to the AACS sample app: * **Additional languages—** The AACS sample app supports the following languages: *US English* (`en-US`), *Australian English* (`en-AU`), *Canadian English* (`en-CA`), *Indian English* (`en-IN`), *British English* (`en-GB`), *German* (d`e-DE`), *Spanish* (`es-ES`), *Mexican Spanish* (`es-MX`), *US Spanish* (`es-US`), *French* (`fr-FR`), *Canadian French* (`fr-CA`), *Hindi* (`hi-IN`), *Italian* (`it-IT`), *Japanese* (`ja-JP`), and *Brazilian Portuguese* (`pr-BR`). The sample app language setting matches the device’s system language setting and syncs the with Alexa as long as the setting is in the supported language list. If Alexa does not support the system language, the sample app GUI defaults to en-US and presents a list of languages for the user to choose from. Once the user selects the language override, the system language does not sync with the sample app again until the user logs out or disables Alexa. * **Network error prompts—** You can configure the sample app to provide feedback to the user when Alexa cannot respond due internet connection issues. The feedback is a voice prompt or an error screen depending on the user action. * **Alexa app assets—** The sample app can show Alexa logos (assets) on the setup screen and display cards instead of showing placeholder assets. * **Comms UI improvements—** Updated the contacts uploading logic in the `Comms UI` AACS app component to ensure the sample app only uploads the contacts for the primary phone. * Updated the AACS Telephony library to get the outgoing phone account using the Android standard API `getDefaultOutgoingPhoneAccount`. AACS Telephony no longer sends an account query intent when receiving the `PhoneCallController.Dial` message from the Auto SDK Engine. * Added a new intent `com.amazon.aacstelephony.bluetooth.connectionCheckCompleted`, which AACS Telephony service broadcasts when it finishes the initial bluetooth connection check. * Updated the `alexa-auto-lwa-auth` app component to use the `Authorization` Auto SDK interface for CBL authorization. **Other changes** * Moved several source code directories within the `aac-sdk` root directory to support the enhanced build system. * Removed `aac-sdk/platforms/android/`. The deprecated Java platform interfaces and JNI are in their respective modules. For example, the Alexa module Java interfaces and JNI are moved from `aac-sdk/platforms/android/modules/alexa/` to `aac-sdk/modules/alexa/android/` * Removed `aac-sdk/extensions/aasb/` because using AASB messages with MessageBroker is the primary Auto SDK API. AASB code for each module is in the respective module directory. For example, the AASB code for the Alexa module is in `aac-sdk/modules/alexa/aasb/`. Note that the AASB message headers to include in your application are not in this directory since they are generated as part of the Auto SDK build output. * Moved `aac-sdk/extensions/system-audio/` to `aac-sdk/modules/system-audio/` * Moved `aac-sdk/extensions/bluetooth/` to `aac-sdk/modules/bluetooth/` * Moved `aac-sdk/extensions/loopback-detector/` to `aac-sdk/modules/loopback-detector/` * Moved `aac-sdk/platforms/android/alexa-auto-client-service/` to `aac-sdk/aacs/android/` * Moved `aac-sdk/platforms/android/alexa-auto-client-service/app-components/` to `aac-sdk/aacs/android/app-components/` * Moved `aac-sdk/samples/android-aacs-sample-app/` to `aac-sdk/aacs/android/sample-app/` * Moved `aac-sdk/platforms/android/alexa-auto-client-service` `/commonutils/` , `/ipc/`, and `/constants/` to `aac-sdk/aacs/android/common/` * Moved AACS media player files to a directory `audioOutput` within `aac-sdk/platforms/android/alexa-auto-client-service/service/` * Moved the Media App Command and Control Android library from `aac-sdk/platforms/android/maccandroid/` to `aac-sdk/aacs/android/service/modules/maccandroid/` * In the LVC extension, the `LocalSearchProvider` AASB messages now have topic `LocalNavigation`. For example, the existing message `LocalSearchProvider.SearchRequest` in 3.3 is `LocalNavigation.SearchRequest` in 4.0. The next major release version of Auto SDK will change the topic back to `LocalSearchProvider`. * Deprecated the option to build AACS as an APK. Starting from Auto SDK 4.0, you can only build AACS as an AAR. * Removed the Android sample app based on the Java platform interfaces. The AACS sample app demonstrates using Auto SDK on Android. **Resolved Issues** * Fixed an issue preventing the generic `DEFAULT` type `LocalMediaSource` from working in offline mode with LVC. * Fixed a race condition in `SpeechRecognizer` in which enabling wake word detection immediately after calling `startCapture()` resulted in a missing call to `stopAudioInput()` when wake word detection was later disabled. * Fixed a deadlock that could occur in an application that uses the deprecated `AuthProvider` interface and starts, stops, and restarts the Engine in quick succession. * Fixed an issue in which Spotify playback commands were delayed on QNX. * Fixed an issue in which the Engine added malformed `PhoneCallController` context to `PhoneCallController` events sent to Alexa. * Fixed an issue in which AACS did not acquire audio focus prior to playing Alexa speech. **Known Issues** **General** * If you do not specify the `deviceSettings.locales` field of the Alexa module configuration, the Engine automatically declares support for the following locale combinations: ["en-US", "es-US"], ["es-US", "en-US"], ["en-IN", "hi-IN"], ["hi-IN", "en-IN"], ["fr-CA", "en-CA"], ["en-CA", "fr-CA"]. The Engine does not automatically declare support for default locale combinations if you assign an empty value to the `locales` field. * The Engine does not persist the `aace.alexa.wakewordEnabled` Engine property setting across device reboots. Your application has to persist the setting and set the property again at each Engine start. AACS implements persisting this property and hence does not have this issue. * If your Linux platform does not use AVX2 instructions, the Amazonlite wake word library initialization causes an illegal instruction error. * When using LVC and stopping the Engine, the `AlexaClient` connection status remains `CONNECTED` because the connection to LVC is not disabled. Your application should not accept user utterances while the Engine is stopped despite the connection status showing `CONNECTED`. * The [Alexa Automotive UX guidelines](https://developer.amazon.com/en-US/docs/alexa/alexa-auto/display-cards.html#dismiss-display-cards) specify when to automatically dismiss a `TemplateRuntime` display card for each template type. The Engine publishes the `TemplateRuntime` interface messages `ClearTemplate` and `ClearPlayerInfo` based on the timeouts configured in the `aace.alexa.templateRuntimeCapabilityAgent` Engine configuration. However, the configuration does not provide enough granularity to specify timeouts for different types of display cards. Consequently, there is no way for your application to configure automatically dismissing local search templates (e.g., `LocalSearchListTemplate2`) with a different timeout than other templates (e.g., `WeatherTemplate`). The configuration also does not provide a way for you to specify infinite timeout for `NowPlaying` cards. You must implement your application’s dismissal logic for display cards and media info accordingly. * When the user requests to view their list of timers on an APL-enabled application, they cannot use an utterance such as “Alexa, scroll up” to scroll through the list shown on the APL card. * There is a rare race condition in which publishing the `AlexaClient.StopForegroundActivity` message does not cancel the active Alexa interaction. The race condition can happen when the application publishes the message at the beginning of the `THINKING` state `AlexaClient.DialogStateChanged` transition. * On the Poky Linux 32-bit platform, the C++ sample app shuts down with an error on launch. * In offline mode with LVC, you might not see the `AlexaClient.DialogStateChanged` `THINKING` state transition if the user invokes Alexa with hold-to-talk and your application provides the audio input data in one large chunk. * In offline mode with LVC, Alexa gets stuck in the `THINKING` state and does not respond after changing the locale setting. The state recovers after a few minutes. * The `CBL` module uses a backoff when refreshing the access token after expiry. If the internet is disconnected when the Engine attempts the refresh, it might take up to a minute to refresh the token after the internet connection is restored. * Some `Core` module messages published by the Engine do not have a corresponding message for the application to report a handling failure. For example, if the user invokes Alexa by tap-to-talk, and the application cannot handle the `AudioInput.StartAudioInput` message, the Engine assumes the application handled the message properly and will provide audio data. As a result, the Engine state and application state might become out of sync. The affected messages are the following: * `AudioInput`: * `StartAudioInput` * `AudioOutput`: * `SetPosition` * `VolumeChanged` * `MutedStateChanged` **Car control** * If you configure the Auto SDK Engine and connect to Alexa using a set of endpoint configurations, you cannot delete any endpoint in the set from Alexa. For example, after you configure set A with endpoints 1, 2, and 3, if you change your car control configuration during development to set B with endpoints 2, 3, and 4, Alexa retains endpoint 1 from set A, which might interfere with resolving the correct endpoint ID for your utterances. However, any endpoint configurations with matching IDs override previous configurations. For example, the configuration of endpoint 2 in set B replaces endpoint 2 in set A. During development, limit configuration changes to create only supersets of previous endpoint configurations. Work with your Solutions Architect or Partner Manager to produce the correct configuration on the first try. **Communications** * Alexa does not understand DTMF utterances that include letters. For example, "press A" and "dial 3*#B" do not result in the correct DTMF directives. * The user might experience unexpected results by trying to dial or place calls in the following ways: * Using utterances that include “double”, “triple”, “hundred”, or “thousand.” For example, calling a number such as 1-800-xxx-xxxx by saying “Alexa call one eight *double oh*...” * Pressing special characters such has “#” or “*” by saying "Alexa press * #." * The user cannot accept or reject incoming Alexa-to-Alexa calls by voice while playing a skill with extended multi-turn dialogs, such as Jeopardy or Skyrim. **Entertainment** * If the user requests Alexa to read notifications while music is playing, they might hear the music play for a split second between the end of one notification and the start of the next. * When an external media player authorization is in progress during Engine shutdown, a rare race condition might cause the Engine to crash. * If your application cancels an Alexa interaction by sending the `AlexaClient.StopForegroundActivity` message to the Engine during music playback, the Engine might erroneously request your application to dismiss the` NowPlaying` media info by publishing the `TemplateRuntime.ClearPlayerInfo` message. Your application should not dismiss the media info in this scenario. * When using the `System Audio` module, Audible and Amazon music might not play correctly on i.MX8 boards. **Local search and navigation** * In offline mode with LVC, after the user requests a list of POIs with an utterance such as “Alexa, find a nearby Starbucks”, Alexa does not recognize followup requests such as "Alexa, select the first one" and does not display or read detailed information about the requested selection. **AACS** * If you do not use the default audio output implementation (i.e., your application handles `AudioOutput` AASB messages), your application will not receive the `AudioOutput.Stop` message if Alexa media is playing when AACS shuts down. As a workaround, your application can listen to `AASB.StopService` or adopt `AACSPinger` to listen to the `STOPPED` state of AACS and stop the media accordingly. **AACS Sample App** * The AACS Sample App does not show the language selection screen when the app is built with Preview Mode. * The AACS Sample App only shows the language selection screen if there is a language mismatch with the system language setting at the first app launch. [Read the SDK Docs](https://alexa.github.io/alexa-auto-sdk/) --- .gitignore | 3 +- BUILDING.md | 730 + CHANGELOG.md | 203 +- CMakeLists.txt | 52 - GETSTARTED.md | 4 +- LICENSE | 203 +- LICENSE_APACHE_V2 | 202 + LINUX_INTEGRATION.md | 95 + MIGRATION.md | 24 +- MIGRATION_TO_AASB_MESSAGEBROKER.md | 316 + NOTICE | 20 +- README.md | 134 +- SDK_MODULES.md | 86 + SECURITY.md | 5 + aacs/android/README.md | 832 + .../app-components/alexa-auto-apis/.gitignore | 0 .../app-components/alexa-auto-apis/README.md | 35 + .../alexa-auto-apis/build.gradle | 50 + .../alexa-auto-apis}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../AnimationProvider.java | 0 .../AssistantManager.java | 0 .../alexaCustomAssistant/EarconProvider.java | 0 .../SettingsProvider.java | 0 .../alexaCustomAssistant/SetupController.java | 0 .../alexaCustomAssistant/SetupProvider.java | 0 .../amazon/alexa/auto/apis/apl/APLTheme.kt | 5 + .../amazon/alexa/auto/apis/app/AlexaApp.java | 0 .../auto/apis/app/AlexaAppRootComponent.java | 0 .../alexa/auto/apis/app/ScopedComponent.java | 0 .../alexa/auto/apis/auth/AuthController.java | 0 .../amazon/alexa/auto/apis/auth/AuthStatus.kt | 0 .../alexa/auto/apis/auth/AuthWorkflow.kt | 3 +- .../auth/AuthorizationHandlerInterface.java | 0 .../apis/communication/BluetoothDevice.kt | 0 .../communication/ContactsController.java | 0 .../auto/apis/login/LoginUIEventListener.java | 0 .../auto/apis/module/ModuleInterface.java | 0 .../session/SessionActivityController.java | 42 + .../apis/session/SessionViewController.java | 0 .../auto/apis/setup/AlexaSetupController.java | 0 .../setup/AlexaSetupWorkflowController.java | 0 .../uxRestrictions/CarUxRestrictionStatus.kt | 10 + .../CarUxRestrictionsController.java | 35 + .../alexa-auto-apl-renderer/.gitignore | 0 .../alexa-auto-apl-renderer/README.md | 157 + .../alexa-auto-apl-renderer/build.gradle | 88 + .../alexa-auto-apl-renderer/gradle.properties | 0 .../alexa-auto-apl-renderer/libs}/.gitignore | 0 .../modules/apl-render/.gitignore | 0 .../modules/apl-render/README.md | 283 + .../modules/apl-render/build.gradle | 74 + .../modules/apl-render/gradle.properties | 0 .../modules/apl-render/lombok.config | 0 .../modules/apl-render}/proguard-rules.pro | 0 .../modules/apl-render/settings.gradle | 0 .../apl-render/src/main/AndroidManifest.xml | 0 .../apl/android/render/APLPresenter.java | 807 + .../apl/android/render/APLSingleton.java | 2 +- .../render/audio/AudioFocusController.java | 0 .../content/APLHttpContentRetriever.java | 2 +- .../render/dagger/ActivityContext.java | 0 .../android/render/dagger/ActivityScope.java | 0 .../render/dagger/ApplicationContext.java | 0 .../render/dagger/ApplicationScope.java | 0 .../dagger/component/ActivityComponent.java | 0 .../component/ApplicationComponent.java | 0 .../dagger/module/APLOptionsModule.java | 13 +- .../render/dagger/module/ActivityModule.java | 0 .../dagger/module/ApplicationModule.java | 0 .../dagger/module/MediaPlayerModule.java | 0 .../render/dagger/module/NetworkModule.java | 0 .../render/dagger/module/TtsModule.java | 0 .../render/extension/ExtensionManager.java | 142 + .../render/extension/back/BackExtension.java | 325 + .../render/extension/back/BackStack.java | 169 + .../extension/back/BackStackDocument.java | 119 + .../render/extension/back/IBackCallback.java | 26 + .../localinfo/LocalInfoExtension.java | 209 + .../render/font/AutoEmbeddedFontResolver.java | 123 + .../interfaces/IAPLContentListener.java | 13 + .../render/interfaces/IAPLEventSender.java | 0 .../IAPLOptionsBuilderProvider.java | 0 .../render/interfaces/IAPLTokenProvider.java | 0 .../render/interfaces/IDismissible.java | 26 + .../interfaces/ILocalInfoDataConsumer.java | 52 + .../interfaces/ILocalInfoDataReporter.java | 31 + .../android/render/interfaces/IPresenter.java | 18 + .../android/render/media/APLMediaPlayer.java | 2 +- .../render/media/APLMediaPlayerProvider.java | 0 .../render/network/NetworkExecutor.java | 0 .../render/network/OkHttpClientWrapper.java | 2 +- .../android/render/payload/APLPayload.java | 2 +- .../render/payload/ExecuteCommandPayload.java | 0 .../render/payload/PresentationSession.java | 2 +- .../render/payload/RenderDocumentPayload.java | 2 +- .../payload/RenderedDocumentStatePayload.java | 0 .../android/render/payload/TimeoutType.java | 0 .../render/payload/UserEventPayload.java | 0 .../apl/android/render/tts/APLTtsPlayer.java | 4 +- .../render/tts/APLTtsPlayerProvider.java | 2 +- .../render/utils/RenderDocumentUtils.java | 0 .../android/render/utils/ViewportUtils.java | 0 .../apl-render/src/main}/libs/.gitignore | 0 .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 42 + .../src/main/assets/APLViewport.json | 113 + .../amazon/alexa/auto/apl/APLDirective.java | 0 .../amazon/alexa/auto/apl/APLFragment.java | 340 + .../alexa/auto/apl/APLThemeDirective.java | 12 + .../com/amazon/alexa/auto/apl/Constants.java | 29 + .../alexa/auto/apl/handler/APLHandler.java | 273 + .../alexa/auto/apl/receiver/APLReceiver.java | 63 + .../auto/apl/receiver/APLThemeReceiver.java | 144 + .../src/main/res/layout/fragment_apl.xml | 19 + .../src/main/res/values/dimens.xml | 5 + .../src/main/res/values/strings.xml | 0 .../auto/apl/TestResourceFileReader.java | 0 .../auto/apl/handler/APLHandlerTest.java | 67 + .../auto/apl/receiver/APLReceiverTest.java | 9 + .../apl/receiver/APLThemeReceiverTest.java | 101 + .../test/resources/aacs/ClearDocument.json | 2 +- .../test/resources/aacs/RenderDocument.json | 2 +- .../aacs/UpdateAPLRuntimeProperties.json | 14 + .../alexa-auto-apps-common-ui/.gitignore | 0 .../alexa-auto-apps-common-ui/README.md | 0 .../alexa-auto-apps-common-ui/build.gradle | 66 + .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../ui/CirclePageIndicatorDecoration.java | 0 .../auto/app/common/ui/LoadingDialog.java | 0 .../auto/app/common/ui/TwoChoiceDialog.java | 0 .../auto/app/common/util/PopupDialogUtil.java | 0 .../alexa/auto/app/common/util/ViewUtils.java | 0 .../drawable/alexa_bubble_small.png | Bin 0 -> 1424 bytes .../res-placeholders/drawable/alexa_logo.png | Bin .../res/color/radio_button_color_selector.xml | 0 .../src/main/res/drawable/ic_close.xml | 0 .../res/drawable/light_button_background.xml | 0 .../drawable/medium_component_background.xml | 0 .../selected_rect_button_background.xml | 0 .../drawable/small_component_background.xml | 0 .../transparent_button_background.xml | 0 .../transparent_rect_button_background.xml | 0 .../main/res/layout/loading_dialog_layout.xml | 0 .../main/res/layout/simple_dialog_layout.xml | 0 .../res/layout/two_choice_dialog_layout.xml | 0 .../src/main/res/values/attrs.xml | 0 .../src/main/res/values/colors.xml | 0 .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/styles.app.xml | 0 .../src/main/res/values/styles.xml | 0 .../main/res/values/theme-alexa-standard.xml | 0 .../app/common/ui/TwoChoiceDialogTest.java | 0 .../alexa-auto-apps-common-util}/.gitignore | 0 .../alexa-auto-apps-common-util/README.md | 10 + .../alexa-auto-apps-common-util/build.gradle | 67 + .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 6 + .../alexa/auto/apps/common/Constants.java | 44 + .../common/aacs/AACSServiceController.java | 3 +- .../apps/common/message/AssistantMessage.java | 0 .../apps/common/util/DNDSettingsProvider.java | 69 + .../util/EarconSoundSettingsProvider.java | 46 + .../alexa/auto/apps/common/util/FileUtil.java | 219 + .../auto/apps/common/util/LocaleUtil.java | 44 + .../auto/apps/common/util/ModuleProvider.java | 7 +- .../auto/apps/common}/util/NetworkUtil.java | 2 +- .../auto/apps/common/util/Preconditions.java | 0 .../auto/apps/common/util/UiThemeManager.java | 315 + .../util/config/AlexaPropertyManager.java | 0 .../common/util/config/LocalesProvider.java | 0 .../aacs/AACSServiceControllerTest.java | 0 .../auto/apps/common/util/FileUtilTest.java | 0 .../apps/common/util/UiThemeManagerTest.java | 128 + .../src/test/resources/aacs_config.json | 0 .../alexa-auto-carcontrol/.gitignore | 0 .../alexa-auto-carcontrol/README.md | 206 + .../aacscarcontrol}/.gitignore | 0 .../aacscarcontrol/build.gradle | 60 + .../aacscarcontrol}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../assets/CarControlEndpointMapping.json | 0 .../AACSCarControlReceiver.java | 0 .../aacscarcontrol/CarControlConstants.java | 0 .../aacscarcontrol/CarControlHandler.java | 0 .../aacscarcontrol/CarControlHelper.java | 0 .../amazon/aacscarcontrol/CarControlUtil.java | 0 .../CarControlHandlerTests.java | 0 .../aacscarcontrol/CarControlHelperTests.java | 0 .../assets/set-fan-speed-to-3.png | Bin .../assets/set-fan-speed-to-3.puml | 0 .../assets/set-reply-to-engine.png | Bin .../assets/set-reply-to-engine.puml | 0 .../alexa-auto-carcontrol/build.gradle | 46 + .../alexa-auto-carcontrol}/gradle.properties | 0 .../alexa-auto-carcontrol/settings.gradle | 9 + .../alexa-auto-comms-ui/.gitignore | 0 .../alexa-auto-comms-ui/README.md | 28 + .../alexa-auto-comms-ui/build.gradle | 81 + .../alexa-auto-comms-ui}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 31 + .../amazon/alexa/auto/comms/ui/Constants.java | 34 + .../auto/comms/ui/ContactsControllerImpl.java | 236 + .../alexa/auto/comms/ui/PreferenceKeys.java | 0 .../alexa/auto/comms/ui/db/BTDevice.java | 0 .../alexa/auto/comms/ui/db/BTDeviceDao.java | 0 .../auto/comms/ui/db/BTDeviceDatabase.java | 0 .../auto/comms/ui/db/BTDeviceRepository.java | 0 .../auto/comms/ui/db/ConnectedBTDevice.java | 0 .../comms/ui/db/ConnectedBTDeviceDao.java | 0 .../ui/db/ConnectedBTDeviceDatabase.java | 0 .../ui/db/ConnectedBTDeviceRepository.java | 198 + .../comms/ui/dependencies/AndroidModule.java | 0 .../dependencies/CommunicationComponent.java | 0 .../ui/dependencies/CommunicationModule.java | 31 + .../settings/CommunicationFragment.java | 0 .../CommunicationPreferenceFragment.java | 0 .../setup/CommunicationConsentFragment.java | 4 +- .../setup/CommunicationConsentViewModel.java | 0 .../ui/handler/BluetoothDirectiveHandler.java | 6 + .../comms/ui/receiver/BluetoothReceiver.java | 86 + .../src/main/res/drawable/ic_arrow_right.xml | 0 .../communication_setup_fragment.xml | 93 + .../layout/communication_consent_layout.xml | 0 .../layout/communication_pair_new_layout.xml | 0 .../communication_preference_layout.xml | 0 .../communication_settings_fragment.xml | 0 .../layout/communication_setup_fragment.xml | 93 + .../navigation/communication_navigation.xml | 0 .../src/main/res/values-de/strings.xml | 21 + .../src/main/res/values-en-rAU/strings.xml | 21 + .../src/main/res/values-en-rCA/strings.xml | 21 + .../src/main/res/values-en-rIN/strings.xml | 21 + .../src/main/res/values-en-rUS/strings.xml | 21 + .../src/main/res/values-en/strings.xml | 21 + .../src/main/res/values-es-rMX/strings.xml | 21 + .../src/main/res/values-es-rUS/strings.xml | 21 + .../src/main/res/values-es/strings.xml | 21 + .../src/main/res/values-fr-rCA/strings.xml | 21 + .../src/main/res/values-fr/strings.xml | 21 + .../src/main/res/values-hi-rIN/strings.xml | 21 + .../src/main/res/values-it/strings.xml | 21 + .../src/main/res/values-ja/strings.xml | 21 + .../src/main/res/values-land/dimens.xml | 24 + .../src/main/res/values-pt-rBR/strings.xml | 21 + .../src/main/res/values/dimens.xml | 28 + .../src/main/res/values/strings.xml | 21 + .../res/xml/communication_preferences.xml | 0 .../CommunicationConsentFragmentTest.java | 0 .../CommunicationConsentViewModelTest.java | 0 .../BluetoothDirectiveHandlerTest.java | 0 .../ui/receiver/BluetoothReceiverTest.java | 0 .../alexa-auto-contacts/README.md | 146 + .../aacscontacts}/.gitignore | 0 .../aacscontacts/build.gradle | 50 + .../aacscontacts}/consumer-rules.pro | 0 .../aacscontacts}/proguard-rules.pro | 0 .../aacscontacts/src/main/AndroidManifest.xml | 0 .../aacscontacts/AACSContactsService.java | 0 .../com/amazon/aacscontacts/Constants.java | 0 .../aacscontacts/PhoneBookController.java | 0 .../res/drawable/alexa_notification_icon.png | Bin .../src/main/res/values/strings.xml | 0 .../PhoneBookControllerTests.java | 0 .../assets/contactsLib-add.png | Bin .../assets/contactsLib-add.puml | 0 .../assets/contactsLib-remove.png | Bin .../assets/contactsLib-remove.puml | 0 .../alexa-auto-contacts/build.gradle | 45 + .../alexa-auto-contacts}/gradle.properties | 0 .../alexa-auto-contacts/settings.gradle | 9 + .../alexa-auto-device-usage}/.gitignore | 0 .../alexa-auto-device-usage/README.md | 38 + .../alexa-auto-device-usage/build.gradle | 0 .../consumer-rules.pro | 0 .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../alexa/auto/deviceusage/AASBReceiver.java | 0 .../auto/deviceusage/DeviceUsageHandler.java | 0 .../NetworkStatsManagerRunner.java | 0 .../src/main/res/values/strings.xml | 0 .../alexa-auto-lwa-auth/.gitignore | 0 .../alexa-auto-lwa-auth/README.md | 0 .../alexa-auto-lwa-auth/build.gradle | 62 + .../alexa-auto-lwa-auth}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 58 + .../alexa/auto/lwa/AlexaClientReceiver.java | 0 .../amazon/alexa/auto/lwa/AuthReceiver.java | 122 + .../alexa/auto/lwa/CBLAuthReceiver.java | 214 + .../alexa/auto/lwa/LWAAuthConstants.java | 26 + .../alexa/auto/lwa/LWAAuthController.java | 496 + .../com/amazon/alexa/auto/lwa/TokenStore.java | 0 .../alexa/auto/lwa/UserIdentityStore.java | 0 .../src/main/res/values/strings.xml | 0 .../alexa-auto-media-player}/.gitignore | 0 .../alexa-auto-media-player/README.md | 74 + .../alexa-auto-media-player/build.gradle | 89 + .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 90 + .../amazon/alexa/auto/media/Constants.java | 0 .../media/MusicStreamAttributeUpdater.java | 0 .../auto/media/ShutdownActionReceiver.java | 61 + .../aacs/handlers/AudioPlayerHandler.java | 354 + .../aacs/handlers/IMediaDuckingObserver.java | 3 + .../aacs/handlers/TemplateRuntimeHandler.java | 0 .../media/browse/AlexaMediaBrowseService.java | 110 +- .../content/AlbumArtContentProvider.java | 0 .../auto/media/dependencies/AACSModule.java | 0 .../media/dependencies/AndroidModule.java | 16 + .../media/dependencies/MediaComponent.java | 0 .../auto/media/dependencies/MediaModule.java | 8 +- .../MediaPlayerAudioFocusController.java | 46 +- .../auto/media/player/MediaPlayerExo.java | 3 +- .../auto/media/player/MediaSourceFactory.java | 149 + .../alexa/auto/media/player/MediaState.kt | 0 .../media/player/NotificationController.java | 5 +- .../auto/media/player/PlaylistParser.java | 0 .../media/session/CustomActionProvider.java | 0 .../media/session/CustomActionProviders.java | 0 .../media/session/MediaMetadataProvider.java | 31 +- .../media/session/MediaSessionManager.java | 792 + .../PlaybackControlButtonActionProvider.java | 0 .../media/session/PlaybackController.java | 109 + .../main/res/drawable/default_album_image.xml | 0 .../src/main/res/drawable/media_dislike.xml | 0 .../res/drawable/media_dislike_selected.xml | 0 .../res/drawable/media_item_place_holder.xml | 0 .../src/main/res/drawable/media_like.xml | 0 .../main/res/drawable/media_like_selected.xml | 0 .../src/main/res/drawable/media_repeat.xml | 0 .../res/drawable/media_repeat_selected.xml | 0 .../src/main/res/drawable/media_shuffle.xml | 0 .../res/drawable/media_shuffle_selected.xml | 0 .../drawable/media_skip_backward_selected.xml | 0 .../drawable/media_skip_forward_selected.xml | 0 .../res/drawable/media_skip_next_disabled.xml | 0 .../drawable/media_skip_previous_disabled.xml | 0 .../src/main/res/layout/msp_option_view.xml | 0 .../src/main/res/values-de/strings.xml | 21 + .../src/main/res/values-en-rAU/strings.xml | 21 + .../src/main/res/values-en-rCA/strings.xml | 21 + .../src/main/res/values-en-rIN/strings.xml | 21 + .../src/main/res/values-en-rUS}/strings.xml | 0 .../src/main/res/values-en/strings.xml | 21 + .../src/main/res/values-es-rMX/strings.xml | 21 + .../src/main/res/values-es-rUS/strings.xml | 21 + .../src/main/res/values-es/strings.xml | 21 + .../src/main/res/values-fr-rCA/strings.xml | 21 + .../src/main/res/values-fr/strings.xml | 21 + .../src/main/res/values-h600dp/dimens.xml | 0 .../src/main/res/values-h600dp/styles.xml | 0 .../src/main/res/values-h600dp/values.xml | 0 .../src/main/res/values-hi-rIN/strings.xml | 21 + .../src/main/res/values-it/strings.xml | 21 + .../src/main/res/values-ja/strings.xml | 21 + .../src/main/res/values-pt-rBR/strings.xml | 21 + .../src/main/res/values/colors.xml | 0 .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/integers.xml | 0 .../src/main/res/values/strings.xml | 23 + .../src/main/res/values/styles.xml | 0 .../src/main/res/values/values.xml | 0 .../browse/AlexaMediaBrowseServiceTest.kt | 0 .../MediaPlayerAudioFocusControllerTest.kt | 0 .../media/session/MediaMetadataProverTest.kt | 0 .../media/session/MediaSessionManagerTest.kt | 36 +- ...PlaybackControlButtonActionProviderTest.kt | 0 .../media/session/PlaybackControllerTest.kt | 0 .../media/session/RenderPlayerInfoBuilder.kt | 0 .../org.mockito.plugins.MockMaker | 0 .../alexa-auto-navigation}/.gitignore | 0 .../alexa-auto-navigation/README.md | 0 .../alexa-auto-navigation/build.gradle | 74 + .../alexa-auto-navigation}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../navigation/dependencies/AACSModule.java | 0 .../dependencies/AndroidModule.java | 0 .../dependencies/GoogleMapsModule.java | 0 .../dependencies/NavigationComponent.java | 0 .../handlers/LocalSearchDirectiveHandler.java | 0 .../handlers/NavigationDirectiveHandler.java | 0 .../navigation/poi/ClearTemplateEvent.java | 0 .../poi/LocalSearchListAdapter.java | 0 .../providers/NavigationProvider.java | 0 .../google/GoogleMapsNavigationProvider.java | 0 .../LocalSearchTemplateRuntimeReceiver.java | 0 .../receiver/NavigationReceiver.java | 0 .../main/res/drawable/circle_background.xml | 0 .../src/main/res/drawable/ic_cancel.xml | 0 .../res/drawable/light_info_background.xml | 0 .../res/drawable/local_search_background.xml | 0 .../main/res/layout/local_search_detail.xml | 4 +- .../src/main/res/layout/local_search_item.xml | 0 .../src/main/res/layout/local_search_list.xml | 4 +- .../src/main/res/values-de/strings.xml | 10 + .../src/main/res/values-en-rAU/strings.xml | 10 + .../src/main/res/values-en-rCA/strings.xml | 10 + .../src/main/res/values-en-rIN/strings.xml | 10 + .../src/main/res/values-en-rUS}/strings.xml | 0 .../src/main/res/values-en/strings.xml | 10 + .../src/main/res/values-es-rMX/strings.xml | 10 + .../src/main/res/values-es-rUS/strings.xml | 10 + .../src/main/res/values-es/strings.xml | 10 + .../src/main/res/values-fr-rCA/strings.xml | 10 + .../src/main/res/values-fr/strings.xml | 10 + .../src/main/res/values-hi-rIN/strings.xml | 10 + .../src/main/res/values-it/strings.xml | 10 + .../src/main/res/values-ja/strings.xml | 10 + .../src/main/res/values-land/dimens.xml | 0 .../src/main/res/values-pt-rBR/strings.xml | 10 + .../src/main/res/values/dimens.xml | 61 + .../src/main/res/values/ids.xml | 0 .../src/main/res/values/strings.xml | 10 + .../src/main/res/values/styles.xml | 0 .../LocalSearchDirectiveHandlerTest.java | 0 .../NavigationDirectiveHandlerTest.java | 0 .../poi/LocalSearchListAdapterTest.java | 0 .../GoogleMapsNavigationProviderTest.java | 0 ...ocalSearchTemplateRuntimeReceiverTest.java | 0 .../receiver/NavigationReceiverTest.java | 0 .../receiver/TestResourceFileReader.java | 0 .../test/resources/aacs/CancelNavigation.json | 0 .../test/resources/aacs/ClearTemplate.json | 0 .../resources/aacs/GetNavigationState.json | 0 .../aacs/RenderTemplateLocalSearchDetail.json | 0 .../aacs/RenderTemplateLocalSearchList.json | 0 .../test/resources/aacs/StartNavigation.json | 0 .../alexa-auto-settings/.gitignore | 0 .../alexa-auto-settings/README.md | 12 + .../alexa-auto-settings/build.gradle | 88 + .../alexa-auto-settings}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 35 + .../src/main/assets/locales.json | 221 + .../auto/settings/AACSMetadataReceiver.java | 6 + .../auto/settings/AACSPreferenceFragment.java | 0 .../AlexaSettingsLanguagesFragment.java | 267 + .../AlexaSoundPreferencesFragment.java | 101 + .../alexa/auto/settings/DNDChangeMessage.java | 17 + .../alexa/auto/settings/DNDReceiver.java | 59 + .../alexa/auto/settings/SettingsActivity.java | 7 + .../settings/SettingsActivityViewModel.java | 36 +- .../auto/settings/config/AACSConfiguration.kt | 0 .../config/AACSConfigurationPreferences.kt | 0 .../settings/config/AACSConfigurator.java | 3 +- .../auto/settings/config/PreferenceKeys.java | 72 + .../settings/dependencies/AACSModule.java | 0 .../settings/dependencies/AndroidModule.java | 0 .../settings/dependencies/ConfigModule.java | 0 .../settings/dependencies/MenuModule.java | 0 .../dependencies/SettingsComponent.java | 8 + .../home/AlexaSettingsHomeFragment.java | 48 +- .../home/AlexaSettingsScreenBuilder.java | 0 .../home/AuthSettingsScreenBuilder.java | 27 +- .../home/DebugSettingsScreenBuilder.java | 0 .../VoiceAssistanceSettingsScreenBuilder.java | 0 .../src/main/res/drawable/ic_arrow_back.xml | 0 .../src/main/res/drawable/ic_check.xml | 0 .../layout/alexa_last_preference_layout.xml | 0 .../res/layout/alexa_preference_layout.xml | 0 .../main/res/layout/navigation_bar_layout.xml | 0 .../res/layout/settings_activity_layout.xml | 0 .../layout/settings_alexa_language_layout.xml | 1535 ++ .../res/navigation/settings_navigation.xml | 12 +- .../src/main/res/values-de/strings.xml | 57 + .../src/main/res/values-en-rAU/strings.xml | 57 + .../src/main/res/values-en-rCA/strings.xml | 57 + .../src/main/res/values-en-rIN/strings.xml | 57 + .../src/main/res/values-en-rUS/strings.xml | 71 + .../src/main/res/values-en/strings.xml | 57 + .../src/main/res/values-es-rMX/strings.xml | 57 + .../src/main/res/values-es-rUS/strings.xml | 57 + .../src/main/res/values-es/strings.xml | 57 + .../src/main/res/values-fr-rCA/strings.xml | 57 + .../src/main/res/values-fr/strings.xml | 57 + .../src/main/res/values-hi-rIN/strings.xml | 57 + .../src/main/res/values-it/strings.xml | 57 + .../src/main/res/values-ja/strings.xml | 57 + .../src/main/res/values-pt-rBR/strings.xml | 57 + .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/strings.xml | 71 + .../src/main/res/values/styles.xml | 0 .../src/main/res/xml/aacs_preferences.xml | 0 .../src/main/res/xml/alexa_preferences.xml | 10 + .../main/res/xml/alexa_sound_preferences.xml | 21 + .../AlexaSoundPreferencesFragmentTest.java | 120 + .../home/AlexaSettingsHomeFragmentTest.java | 15 + .../home/AuthSettingsScreenBuilderTest.java | 0 .../home/DebugSettingsScreenBuilderTest.java | 0 ...ceAssistanceSettingsScreenBuilderTest.java | 0 .../alexa-auto-setup/.gitignore | 0 .../app-components/alexa-auto-setup/README.md | 26 + .../alexa-auto-setup/build.gradle | 79 + .../alexa-auto-setup}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../CBLLoginWorkflowSpecification.json | 0 ...PreviewModeLoginWorkflowSpecification.json | 0 .../setup/dependencies/AndroidModule.java | 0 .../auto/setup/dependencies/ConfigModule.java | 0 .../setup/dependencies/SetupComponent.java | 85 + .../setup/dependencies/WorkflowModule.java | 0 .../receiver/NetworkStateChangeReceiver.java | 45 + .../AlexaSetupWorkflowControllerImpl.java | 0 .../alexa/auto/setup/workflow/Workflow.java | 0 .../auto/setup/workflow/WorkflowMessage.java | 0 .../setup/workflow/WorkflowNavigator.java | 0 .../auto/setup/workflow/WorkflowProvider.java | 0 .../auto/setup/workflow/WorkflowStep.java | 0 .../CheckContactsConsentStatusCommand.java | 0 .../command/CheckLanguageCommand.java | 0 .../command/CheckLocationConsentCommand.java | 0 .../command/CheckLoginRequiredCommand.java | 2 +- .../command/CheckNetworkStatusCommand.java | 0 .../auto/setup/workflow/command/Command.java | 0 .../command/SetupCompleteCommand.java | 0 .../auto/setup/workflow/event/LoginEvent.java | 0 .../workflow/event/VoiceAssistanceEvent.java | 0 .../AuthProviderAuthenticatedFragment.java | 0 .../setup/workflow/fragment/CBLFragment.java | 27 + .../fragment/CBLLoginErrorFragment.java | 0 .../fragment/CBLLoginFinishFragment.java | 0 .../setup/workflow/fragment/CBLViewModel.java | 21 +- .../fragment/EnablePreviewModeFragment.java | 159 + .../fragment/EnablePreviewModeViewModel.java | 0 .../fragment/LanguageSelectionFragment.java | 0 .../fragment/LocationConsentFragment.java | 0 .../workflow/fragment/LoginFragment.java | 32 +- .../workflow/fragment/LoginViewModel.java | 0 .../workflow/fragment/NetworkFragment.java | 0 .../workflow/fragment/NetworkViewModel.java | 0 .../fragment/SetupNotCompleteFragment.java | 0 .../setup/workflow/model/LocationConsent.java | 0 .../setup/workflow/util/QRCodeGenerator.java | 0 .../src/main/res/drawable/ic_wifi_help.xml | 0 .../auth_provider_login_finished.xml | 128 + .../main/res/layout-land/cbl_code_loading.xml | 0 .../main/res/layout-land/cbl_login_error.xml | 66 + .../res/layout-land/cbl_login_finished.xml | 101 + .../res/layout-land/enable_preview_mode.xml | 91 + .../main/res/layout-land/location_consent.xml | 97 + .../layout-land/login_display_cbl_code.xml | 80 + .../src/main/res/layout-land/login_start.xml | 75 + .../main/res/layout-land/network_fragment.xml | 82 + .../res/layout-land/setup_not_complete.xml | 67 + .../layout-land/start_language_selection.xml | 55 + .../res/layout/aacs_connection_loading.xml | 0 .../layout/auth_provider_login_finished.xml | 131 + .../src/main/res/layout/cbl_code_loading.xml | 0 .../src/main/res/layout/cbl_fragment.xml | 0 .../src/main/res/layout/cbl_login_error.xml | 67 + .../main/res/layout/cbl_login_finished.xml | 104 + .../main/res/layout/enable_preview_mode.xml | 93 + .../src/main/res/layout/location_consent.xml | 97 + .../res/layout/login_display_cbl_code.xml | 82 + .../src/main/res/layout/login_fragment.xml | 0 .../src/main/res/layout/login_start.xml | 75 + .../src/main/res/layout/network_fragment.xml | 82 + .../main/res/layout/setup_not_complete.xml | 67 + .../res/layout/start_language_selection.xml | 54 + .../main/res/navigation/setup_navigation.xml | 2 +- .../src/main/res/values-de/strings.xml | 51 + .../src/main/res/values-en-rAU/strings.xml | 51 + .../src/main/res/values-en-rCA/strings.xml | 51 + .../src/main/res/values-en-rIN/strings.xml | 51 + .../src/main/res/values-en-rUS/strings.xml | 51 + .../src/main/res/values-en/strings.xml | 51 + .../src/main/res/values-es-rMX/strings.xml | 51 + .../src/main/res/values-es-rUS/strings.xml | 51 + .../src/main/res/values-es/strings.xml | 51 + .../src/main/res/values-fr-rCA/strings.xml | 51 + .../src/main/res/values-fr/strings.xml | 52 + .../src/main/res/values-hi-rIN/strings.xml | 51 + .../src/main/res/values-it/strings.xml | 51 + .../src/main/res/values-ja/strings.xml | 51 + .../src/main/res/values-land/dimens.xml | 28 + .../src/main/res/values-pt-rBR/strings.xml | 51 + .../src/main/res/values/dimens.xml | 34 + .../src/main/res/values/strings.xml | 51 + .../workflow/TestResourceFileReader.java | 0 .../setup/workflow/WorkflowNavigatorTest.java | 0 .../setup/workflow/WorkflowProviderTest.java | 0 .../CheckLocationConsentCommandTest.java | 0 .../command/SetupCompleteCommandTest.java | 0 ...AuthProviderAuthenticatedFragmentTest.java | 0 .../workflow/fragment/CBLFragmentTest.java | 0 .../fragment/CBLLoginErrorFragmentTest.java | 0 .../fragment/CBLLoginFinishFragmentTest.java | 0 .../workflow/fragment/CBLViewModelTest.java | 12 + .../EnablePreviewModeFragmentTest.java | 0 .../LanguageSelectionFragmentTest.java | 0 .../fragment/LocationConsentFragmentTest.java | 0 .../workflow/fragment/LoginFragmentTest.java | 0 .../workflow/fragment/LoginViewModelTest.java | 0 .../fragment/NetworkFragmentTest.java | 0 .../SetupNotCompleteFragmentTest.java | 0 .../NetworkStateChangeReceiverTest.java | 0 .../CBLLoginWorkflowSpecification.json | 0 .../alexa-auto-telephony/.gitignore | 0 .../alexa-auto-telephony/README.md | 212 + .../aacstelephony}/.gitignore | 0 .../aacstelephony/build.gradle | 52 + .../aacstelephony}/consumer-rules.pro | 0 .../aacstelephony}/proguard-rules.pro | 0 .../ExampleInstrumentedTest.java | 0 .../src/main/AndroidManifest.xml | 0 .../aacstelephony/AACSTelephonyService.java | 50 +- .../aacstelephony/BluetoothStateListener.java | 1 + .../com/amazon/aacstelephony/CallMap.java | 0 .../aacstelephony/CallStateListener.java | 0 .../com/amazon/aacstelephony/Constants.java | 0 .../aacstelephony/PhoneCallController.java | 387 + .../java/com/amazon/aacstelephony/Util.java | 21 + .../res/drawable/alexa_notification_icon.png | Bin .../src/main/res/values/strings.xml | 0 .../BluetoothStateListenerTest.java | 0 .../aacstelephony/CallStateListenerTest.java | 0 .../PhoneCallControllerTest.java | 0 .../assets/AACSTelephony_initiateCall.png | Bin .../assets/AACSTelephony_initiateCall.puml | 0 .../alexa-auto-telephony/build.gradle | 46 + .../alexa-auto-telephony}/gradle.properties | 0 .../alexa-auto-telephony/settings.gradle | 9 + .../.gitignore | 8 + .../README.md | 0 .../build.gradle | 77 + .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../dependencies/AACSModule.java | 0 .../dependencies/AndroidModule.java | 0 .../TemplateRuntimeComponent.java | 0 .../receiver/AlexaStateChangeReceiver.java | 0 .../AlexaVoiceoverCompletedMessage.java | 0 .../receiver/TemplateRuntimeReceiver.java | 0 .../weather/WeatherAdapter.java | 0 .../weather/WeatherDirectiveHandler.java | 4 + .../res/drawable/display_card_background.xml | 0 .../src/main/res/drawable/ic_cancel.xml | 0 .../src/main/res/layout/weather.xml | 87 + .../src/main/res/layout/weather_current.xml | 0 .../src/main/res/layout/weather_forecast.xml | 0 .../main/res/layout/weather_forecast_day.xml | 0 .../src/main/res/values-land/dimens.xml | 0 .../src/main/res/values/dimens.xml | 59 + .../src/main/res/values/ids.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/values/styles.xml | 0 .../common/TestResourceFileReader.java | 0 .../AlexaStateChangeReceiverTest.java | 0 .../receiver/TemplateRuntimeReceiverTest.java | 0 .../weather/WeatherAdapterTest.java | 0 .../weather/WeatherDirectiveHandlerTest.java | 0 .../test/resources/aacs/ClearTemplate.json | 0 .../aacs/DialogStateChangedIdle.json | 0 .../aacs/DialogStateChangedListening.json | 0 .../resources/aacs/RenderTemplateWeather.json | 0 .../app-components/alexa-auto-tts/README.md | 181 + .../alexa-auto-tts/aacstts/.gitignore | 8 + .../alexa-auto-tts/aacstts/build.gradle | 53 + .../aacstts}/proguard-rules.pro | 0 .../aacstts/src/main/AndroidManifest.xml | 0 .../java/com/amazon/aacstts/AACSUtil.java | 0 .../aacstts/AmazonTextToSpeechService.java | 0 .../java/com/amazon/aacstts/AudioDecoder.java | 0 .../java/com/amazon/aacstts/ISO3CodeUtil.java | 0 .../java/com/amazon/aacstts/JSONUtil.java | 0 .../com/amazon/aacstts/MessageHandler.java | 0 .../amazon/aacstts/SynthesizeTextUtil.java | 0 .../java/com/amazon/aacstts/TTSConstants.java | 0 .../com/amazon/aacstts/TTSIntentReceiver.java | 0 .../amazon/aacstts/handler/AASBHandler.java | 0 .../aacstts/handler/AlexaClientHandler.java | 0 .../aacstts/handler/IAACSMessageHandler.java | 0 .../amazon/aacstts/handler/TTSHandler.java | 0 .../models/GetCapabilitiesPayload.java | 0 .../models/PrepareSpeechMessageOptions.java | 0 .../models/PrepareSpeechMessagePayload.java | 0 .../aacstts/models/ProviderVoiceItem.java | 0 .../models/TTSSynthesisFutureResponse.java | 0 .../aacstts/src/main/res/values/strings.xml | 0 .../aacstts/AlexaClientHandlerTests.java | 0 .../AmazonTextToSpeechServiceTests.java | 0 .../aacstts/SynthesizeTextUtilTests.java | 0 .../com/amazon/aacstts/TTSHandlerTests.java | 0 .../java/com/amazon/aacstts/TestAACSUtil.java | 0 .../alexa-auto-tts/assets/Android_TTS.png | Bin .../alexa-auto-tts/assets/Android_TTS.xml | 0 .../alexa-auto-tts/build.gradle | 27 + .../alexa-auto-tts}/gradle.properties | 0 .../alexa-auto-tts/settings.gradle | 0 .../alexa-auto-ux-restrictions/.gitignore | 8 + .../alexa-auto-ux-restrictions/README.md | 10 + .../alexa-auto-ux-restrictions/build.gradle | 61 + .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 15 + .../modules-uxrestrictions.json | 5 + .../CarUxRestrictionsModule.java | 136 + .../DefaultCarUxRestrictionsController.java | 109 + .../src/main/res/values/strings.xml | 4 + .../alexa-auto-voice-interaction/.gitignore | 0 .../alexa-auto-voice-interaction/README.md | 10 + .../alexa-auto-voice-interaction/build.gradle | 72 + .../gradle.properties | 0 .../proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../common/AutoVoiceInteractionMessage.java | 0 .../voiceinteraction/common/Constants.java | 0 .../receiver/AACSBroadcastReceiver.java | 74 + .../service/AutoVoiceInteractionService.java | 28 +- .../service/AutoVoiceInteractionSession.java | 51 + .../AutoVoiceInteractionSessionService.java | 0 .../src/main/res/values/strings.xml | 0 .../xml/auto_voice_interaction_service.xml | 0 .../TestResourceFileReader.java | 0 .../receiver/AACSBroadcastReceiverTest.java | 106 + .../ConnectionStatusChangedConnected.json | 0 .../ConnectionStatusChangedDisconnected.json | 0 .../test/resources/aacs/WakewordDetected.json | 0 .../alexa-auto-voice-ui/.gitignore | 9 + .../alexa-auto-voice-ui/README.md | 11 + .../alexa-auto-voice-ui/build.gradle | 73 + .../alexa-auto-voice-ui}/gradle.properties | 0 .../alexa-auto-voice-ui}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 34 + .../alexa/auto/voice/ui/VoiceActivity.java | 426 + .../voice/ui/common/AutoVoiceUIMessage.java | 30 + .../alexa/auto/voice/ui/common/Constants.java | 13 + .../voice/ui/earcon/EarconController.java | 122 + .../ui/receiver/AACSBroadcastReceiver.java | 78 + .../SessionActivityControllerImpl.java | 48 + .../session/SessionViewControllerImpl.java | 2 +- .../layout/autovoiceinteraction_layout.xml | 0 .../main/res/raw-de/auto_error_offline.mp3 | Bin 0 -> 29997 bytes .../res/raw-en-rAU/auto_error_offline.mp3 | Bin 0 -> 25245 bytes .../res/raw-en-rCA/auto_error_offline.mp3 | Bin 0 -> 27405 bytes .../res/raw-en-rIN/auto_error_offline.mp3 | Bin 0 -> 28989 bytes .../res/raw-en-rUS/auto_error_offline.mp3 | Bin 0 -> 22797 bytes .../main/res/raw-en/auto_error_offline.mp3 | Bin 0 -> 28989 bytes .../res/raw-es-rMX/auto_error_offline.mp3 | Bin 0 -> 28989 bytes .../res/raw-es-rUS/auto_error_offline.mp3 | Bin 0 -> 31149 bytes .../main/res/raw-es/auto_error_offline.mp3 | Bin 0 -> 30429 bytes .../res/raw-fr-rCA/auto_error_offline.mp3 | Bin 0 -> 28701 bytes .../main/res/raw-fr/auto_error_offline.mp3 | Bin 0 -> 24381 bytes .../res/raw-hi-rIN/auto_error_offline.mp3 | Bin 0 -> 31869 bytes .../main/res/raw-it/auto_error_offline.mp3 | Bin 0 -> 27261 bytes .../main/res/raw-ja/auto_error_offline.mp3 | Bin 0 -> 33021 bytes .../res/raw-pt-rBR/auto_error_offline.mp3 | Bin 0 -> 23373 bytes .../src/main/res/raw/auto_error_offline.mp3 | Bin 0 -> 22797 bytes .../src/main/res/raw/med_ui_endpointing.wav | Bin .../src/main/res/raw/med_ui_wakesound.wav | Bin .../main/res/raw/med_ui_wakesound_touch.wav | Bin .../src/main/res/values-land/dimens.xml | 0 .../src/main/res/values/dimens.xml | 0 .../src/main/res/values/strings.xml | 3 + .../src/main/res/values/styles.xml | 28 + .../auto/voice/ui/TestResourceFileReader.java | 25 + .../receiver/AACSBroadcastReceiverTest.java | 132 + .../SessionActivityControllerImplTest.java | 67 + .../SessionViewControllerImplTest.java | 2 +- .../aacs/DialogStateChangedIdle.json | 2 +- .../aacs/DialogStateChangedListening.json | 2 +- .../aacs/DialogStateChangedSpeaking.json | 2 +- .../aacs/DialogStateChangedThinking.json | 2 +- .../test/resources/aacs/WakewordDetected.json | 14 + .../android}/assets/AACSArchDetailed.png | Bin .../android}/assets/AACSInit.puml | 0 .../android}/assets/AACSInitFlow.png | Bin .../android}/assets/AACSWakeword.png | Bin .../android}/assets/AACSWakeword.puml | 0 aacs/android/assets/AACS_CBLLogin.png | Bin 0 -> 86098 bytes aacs/android/assets/AACS_CBLLogin.puml | 55 + .../android}/assets/APCP.png | Bin aacs/android/assets/config.json | 105 + .../android/common}/commonutils/.gitignore | 0 .../android/common}/commonutils/README.md | 0 .../commonutils/aacscommonutils}/.gitignore | 0 .../commonutils/aacscommonutils/build.gradle | 45 + .../aacscommonutils}/consumer-rules.pro | 0 .../aacscommonutils}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../common/AACSComponentRegistryUtil.java | 0 .../alexa/auto/aacs/common/AACSMessage.java | 0 .../auto/aacs/common/AACSMessageBuilder.java | 4 +- .../auto/aacs/common/AACSMessageSender.java | 0 .../auto/aacs/common/AACSReplyMessage.java | 0 .../ConnectionStatusChangedMessages.java | 0 .../common/DialogStateChangedMessages.java | 0 .../auto/aacs/common/LocalSearchCommon.kt | 0 .../aacs/common/LocalSearchDetailTemplate.kt | 0 .../aacs/common/LocalSearchListTemplate.kt | 0 .../auto/aacs/common/NavigationMessages.java | 0 .../aacs/common/PlaybackControlMessages.java | 108 + .../auto/aacs/common/RenderPlayerInfo.kt | 6 +- .../aacs/common/SpeechRecognizerMessages.java | 0 .../alexa/auto/aacs/common/StartNavigation.kt | 0 .../aacs/common/TemplateRuntimeMessages.java | 0 .../aacs/common/WakewordDetectedMessages.java | 0 .../alexa/auto/aacs/common/WeatherTemplate.kt | 0 .../aacs/common/AACSMessageBuilderTest.java | 0 .../aacs/common/AACSMessageSenderTest.java | 0 .../ConnectionStatusChangedMessagesTest.java | 0 .../DialogStateChangedMessagesTest.java | 0 .../aacs/common/NavigationMessagesTest.java | 0 .../common/PlaybackControlMessagesTest.java | 0 .../common/SpeechRecognizerMessagesTest.java | 0 .../common/TemplateRuntimeMessagesTest.java | 0 .../aacs/common/TestResourceFileReader.java | 0 .../aacs/LocalSearchDetailTemplateV1.json | 0 .../aacs/LocalSearchListTemplateV2.json | 0 .../test/resources/aacs/StartNavigation.json | 0 .../aacs/TemplateRuntimePlayerRenderInfo.json | 0 aacs/android/common/commonutils/build.gradle | 46 + .../common/commonutils}/gradle.properties | 0 .../common/commonutils/settings.gradle | 7 + .../android/common}/constants/.gitignore | 0 .../constants/aacsconstants}/.gitignore | 0 .../constants/aacsconstants/build.gradle | 32 + .../aacsconstants}/consumer-rules.pro | 0 .../aacsconstants}/proguard-rules.pro | 0 .../ExampleInstrumentedTest.java | 0 .../src/main/AndroidManifest.xml | 0 .../amazon/aacsconstants/AACSConstants.java | 11 +- .../aacsconstants/AACSPropertyConstants.java | 2 + .../amazon/aacsconstants/AASBConstants.java | 16 + .../java/com/amazon/aacsconstants/Action.java | 23 + .../aacsconstants/ContactsConstants.java | 0 .../amazon/aacsconstants/MediaConstants.java | 6 + .../aacsconstants/NavigationConstants.java | 0 .../aacsconstants/NetworkConstants.java | 0 .../aacsconstants/PlaybackConstants.java | 7 + .../aacsconstants/TelephonyConstants.java | 1 + .../TemplateRuntimeConstants.java | 0 .../java/com/amazon/aacsconstants/Topic.java | 2 + .../amazon/aacsconstants/ExampleUnitTest.java | 0 aacs/android/common/constants/build.gradle | 27 + .../common/constants}/gradle.properties | 0 .../android/common}/constants/settings.gradle | 0 .../android/common/ipc}/.gitignore | 0 aacs/android/common/ipc/README.md | 213 + .../android/common/ipc/aacsipc}/.gitignore | 0 .../android/common}/ipc/aacsipc/build.gradle | 0 .../common/ipc/aacsipc}/proguard-rules.pro | 0 .../aacsipc/ExampleInstrumentedTest.java | 0 .../ipc/aacsipc/src/main/AndroidManifest.xml | 0 .../java/com/amazon/aacsipc/AACSPinger.java | 0 .../java/com/amazon/aacsipc/AACSReceiver.java | 0 .../java/com/amazon/aacsipc/AACSSender.java | 11 + .../java/com/amazon/aacsipc/IPCConstants.java | 0 .../java/com/amazon/aacsipc/SenderMap.java | 0 .../com/amazon/aacsipc/TargetComponent.java | 0 .../java/com/amazon/aacsipc/DummyService.java | 0 .../com/amazon/aacsipc/TestAACSReceiver.java | 0 .../com/amazon/aacsipc/TestAACSSender.java | 0 .../java/com/amazon/aacsipc/TestUtils.java | 0 aacs/android/common/ipc/build.gradle | 26 + .../android/common}/ipc/gradle.properties | 0 .../android/common}/ipc/settings.gradle | 0 aacs/android/conanfile.py | 44 + aacs/android/restrictedAssets/LICENSE_PMLA | 9 + aacs/android/restrictedAssets/NOTICE | 1 + .../drawable/alexa_bubble_small.png | Bin 0 -> 983 bytes .../restrictedAssets/drawable/alexa_logo.png | Bin 0 -> 5141 bytes .../android/sample-app}/.gitignore | 0 aacs/android/sample-app/README.md | 413 + .../sample-app/alexa-auto-app/.gitignore | 9 + .../assets/AACSSampleAppArch.png | Bin .../AACSSampleAppComponentDiagram.drawio | 1 + .../assets/AACSSampleAppComponentDiagram.png | Bin 0 -> 150420 bytes .../sample-app/alexa-auto-app/build.gradle | 185 + .../alexa-auto-app}/gradle.properties | 0 .../alexa-auto-app}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 46 + .../src/main/assets/config/aacs_config.json | 90 + .../alexa/auto/app/AutoApplication.java | 0 .../com/amazon/alexa/auto/app/Constants.java | 0 .../app/DefaultAlexaAppRootComponent.java | 0 .../alexa/auto/app/audio/AudioIOService.java | 0 .../auto/app/audio/AudioIOServiceWorker.java | 0 .../auto/app/audio/AudioInputHandler.java | 0 .../auto/app/audio/AudioInputReader.java | 0 .../AudioServiceNotificationBuilder.java | 5 +- .../auto/app/dependencies/AACSModule.java | 0 .../auto/app/dependencies/AlexaAppModule.java | 0 .../auto/app/dependencies/AlexaAppScope.java | 0 .../app/dependencies/AndroidAppModule.java | 0 .../auto/app/dependencies/AppComponent.java | 0 .../app/dependencies/AudioIOComponent.java | 0 .../auto/app/dependencies/AudioIOModule.java | 0 .../auto/app/dependencies/ServiceScope.java | 0 .../app/setup/AlexaSetupControllerImpl.java | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/xml/filepaths.xml | 0 .../auto/app/audio/AudioIOServiceTest.java | 0 .../auto/app/audio/AudioInputHandlerTest.java | 0 .../auto/app/audio/AudioInputReaderTest.java | 0 aacs/android/sample-app/build.gradle | 124 + aacs/android/sample-app/gradle.properties | 14 + .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 .../android/sample-app}/gradlew | 0 aacs/android/sample-app/settings.gradle | 138 + aacs/android/service/.gitignore | 7 + aacs/android/service/README.md | 420 + aacs/android/service/build.gradle | 124 + .../android/service/core-service}/.gitignore | 0 .../android/service/core-service/build.gradle | 276 + .../assets/file-util-res/aacs_config.json | 223 + .../assets/file-util-res/auto_sdk_config.json | 3 - .../TestAlexaAutoClientService.java | 0 .../instrumentedtest/TestFileUtil.java | 0 .../instrumentedtest/TestUtil.java | 0 .../src/debug/AndroidManifest.xml | 0 .../AACSMessageLogger.java | 0 .../amazon/alexaautoclientservice/README.md | 0 .../constants/MessageLoggerConstants.java | 0 .../receiver/InstrumentationReceiver.java | 0 .../core-service/src/main/AndroidManifest.xml | 80 + .../aidl/com/amazon/alexalve/ILVCClient.aidl | 0 .../aidl/com/amazon/alexalve/ILVCService.aidl | 0 .../src/main/assets/certs/09789157.0 | 0 .../src/main/assets/certs/3513523f.0 | 0 .../src/main/assets/certs/6d41d539.0 | 0 .../src/main/assets/certs/85cf5865.0 | 0 .../src/main/assets/certs/8cb5ee0f.0 | 0 .../src/main/assets/certs/b204d74a.0 | 0 .../src/main/assets/certs/ce5e74ef.0 | 0 .../src/main/assets/certs/de6d66f3.0 | 0 .../src/main/assets/certs/f387163d.0 | 0 .../AACSPropertyContentProvider.java | 0 .../alexaautoclientservice/AASBHandler.java | 47 +- .../AlexaAutoClientService.java | 115 +- .../ComponentRegistry.java | 192 + .../ConfigMessageReceivedCallback.java | 6 +- .../LVCInteractionProvider.java | 0 .../NotificationListener.java | 0 .../constants/AudioSourceConstants.java | 0 .../constants/ConfigFieldConstants.java | 20 + .../constants/LVCServiceConstants.java | 0 .../AlexaClientMessageHandler.java | 41 + .../alexaClient/AuthStateObserver.java | 0 .../alexaClient/ConnectionStateObserver.java | 0 .../alexaClient/DialogStateObserver.java | 20 + .../audioInput/AudioInputFocusManager.java | 135 + .../audioInput/AudioInputMessageHandler.java | 8 +- .../AudioOutputMessageHandler.java | 23 +- .../mediaPlayer/AACSMediaPlayer.java | 6 + .../mediaPlayer/AudioFocusAttributes.java | 10 +- .../mediaPlayer/EventReceiver.java | 0 .../mediaPlayer/exo/ExoPlayerHandler.java | 188 +- .../mediaPlayer/exo/MediaSourceFactory.java | 194 + .../mediaPlayer/exo/PlaylistParser.java | 110 + .../raw/RawAudioOutputHandler.java | 290 + .../bluetooth/BluetoothProviderHandler.java | 2 +- .../BluetoothServerSocketHandler.java | 2 +- .../bluetooth/BluetoothSocketHandler.java | 2 +- .../CustomDomainMessageDispatcher.java | 134 + .../IDiscoveredPlayerProvider.java | 0 .../externalMediaPlayer/MACCPlayer.java | 0 .../LocationProviderHandler.java | 0 .../mediaManager/LocalMediaSourceHandler.java | 687 + .../mediaManager/LocalSessionHandler.java | 0 .../modules/mediaManager/MediaSource.java | 0 .../NetworkInfoProviderHandler.java | 0 .../PropertyManagerHandler.java | 51 + .../receiver/LVCReceiver.java | 2 +- .../receiver/PingReceiver.java | 0 .../ServiceMetadataRequestReceiver.java | 0 .../receiver/StartOnBootReceiver.java | 0 .../SystemPropertyChangeReceiver.java | 211 + .../util/AACSStateObserver.java | 0 .../alexaautoclientservice/util/AASBUtil.java | 0 .../alexaautoclientservice/util/FileUtil.java | 890 + .../util/MediaPlayerUtil.java | 73 + .../util/PropertyUtil.java | 71 + .../res/drawable/alexa_notification_icon.png | Bin .../src/main/res/values/strings.xml | 0 .../AACSMessageLogger.java | 0 .../receiver/InstrumentationReceiver.java | 0 .../unittest/TestAASBHandler.java | 0 aacs/android/service/gradle.properties | 15 + .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 4 +- .../android => aacs/android/service}/gradlew | 0 .../service/modules/aacs-extra/build.gradle | 30 + .../modules/aacs-extra}/consumer-rules.pro | 0 .../modules/aacs-extra}/proguard-rules.pro | 0 .../aacs-extra/src/main/AndroidManifest.xml | 0 .../aacs_extra/AACSContext.java | 0 .../AACSModuleFactoryInterface.java | 0 .../aacs_extra/EngineStatusListener.java | 0 .../service/modules/maccandroid}/.gitignore | 0 .../service/modules/maccandroid/build.gradle | 63 + .../modules/maccandroid}/proguard-rules.pro | 0 .../maccandroid/src/main/AndroidManifest.xml | 0 .../DiscoverAndReportMediaAppsHandler.java | 3 +- .../main/java/com/amazon/maccandroid/Log.java | 0 .../amazon/maccandroid/MACCAndroidClient.java | 0 .../MACCAndroidClientCallback.java | 0 .../java/com/amazon/maccandroid/MediaApp.java | 0 .../MediaAppsConnectionListener.java | 0 .../MediaAppsDirectivesHandler.java | 0 .../maccandroid/MediaAppsRepository.java | 0 .../maccandroid/MediaAppsStateReporter.java | 0 .../maccandroid/MediaControllerCallback.java | 0 .../maccandroid/model/APIConstants.java | 0 .../model/Directive/AdjustSeekDirective.java | 0 .../model/Directive/Directive.java | 0 .../model/Directive/LoginDirective.java | 0 .../model/Directive/LogoutDirective.java | 0 .../model/Directive/PlayControlDirective.java | 0 .../model/Directive/PlayDirective.java | 0 .../model/Directive/SeekDirective.java | 0 .../maccandroid/model/PackageMetadata.java | 0 .../model/PlayBackStateFields.java | 0 .../maccandroid/model/PlayerEvents.java | 0 .../maccandroid/model/PlayerPlaybackInfo.java | 0 .../model/SupportedOperations.java | 0 .../model/errors/CapabilityAgentError.java | 0 .../model/errors/MediaAppPlayerError.java | 0 .../model/players/AuthorizedPlayer.java | 0 .../model/players/DiscoveredPlayer.java | 0 .../model/state/ExternalMediaPlayerState.java | 0 .../model/state/MediaAppMetaData.java | 0 .../model/state/MediaAppPlaybackState.java | 0 .../model/state/MediaAppSessionState.java | 0 ...DiscoverAndReportMediaAppsHandlerTest.java | 0 .../amazon/maccandroid/ExampleUnitTest.java | 0 .../MediaAppsDirectivesHandlerTest.java | 0 .../maccandroid/MediaAppsRepositoryTest.java | 0 .../MediaControllerCallbackTest.java | 0 .../com/amazon/maccandroid/ShadowJobInfo.java | 0 .../com/amazon/maccandroid/ShadowUri.java | 0 aacs/android/service/settings.gradle | 62 + assets/Migration-ApplicationArch.png | Bin 0 -> 52957 bytes assets/Migration-Hybrid.png | Bin 0 -> 43317 bytes assets/Migration-Steps.png | Bin 0 -> 132433 bytes assets/aac_architecture.png | Bin 110217 -> 0 bytes assets/aac_linux_integration.png | Bin 0 -> 22351 bytes builder/.gitignore | 8 +- builder/README.md | 596 +- builder/build.py | 321 + builder/build.sh | 35 - builder/hosttools/pkg-config | 44 - .../qnx7-pkgconfig/aarch64le/libcrypto.pc | 13 - .../qnx7-pkgconfig/x86_64/libcrypto.pc | 13 - .../meta-aac-builder/classes/aac-base.bbclass | 35 - .../classes/aac-image.bbclass | 23 - builder/meta-aac-builder/conf/conf-notes.txt | 24 - builder/meta-aac-builder/conf/distro/aac.conf | 49 - .../conf/distro/include/tclibc-android.inc | 14 - .../conf/distro/include/tclibc-qnx.inc | 4 - .../conf/distro/include/tcmode-external.inc | 8 - builder/meta-aac-builder/conf/layer.conf | 12 - .../meta-aac-builder/conf/local.conf.sample | 33 - .../conf/machine/androidarm.conf | 13 - .../conf/machine/androidarm64.conf | 14 - .../conf/machine/androidx86-64.conf | 10 - .../conf/machine/androidx86.conf | 9 - .../conf/machine/include/android.inc | 96 - .../conf/machine/include/linaro.inc | 27 - .../conf/machine/include/poky.inc | 33 - .../conf/machine/include/qnx7.inc | 63 - .../conf/machine/linaroarm64.conf | 12 - .../conf/machine/linaroarmel.conf | 7 - .../conf/machine/linaroarmhf.conf | 12 - .../meta-aac-builder/conf/machine/native.conf | 45 - .../conf/machine/pokyarm.conf | 9 - .../conf/machine/pokyarm64.conf | 9 - .../conf/machine/qnx7arm64.conf | 13 - .../conf/machine/qnx7x86-64.conf | 13 - .../mbedtls/mbedtls_2.16.2.bb | 14 - .../nghttp2/nghttp2_%.bbappend | 2 - .../openssl/openssl_1.1.0%.bbappend | 41 - .../recipes-core/images/aac-sdk-build.bb | 20 - .../recipes-devtools/asio/asio_1.12.2.bb | 15 - .../cmake/cmake-native_3.8.2.bb | 25 - .../nlohmann/nlohmann_3.7.1.bb | 15 - .../protobuf/protobuf_%.bbappend | 1 - .../rapidjson/rapidjson_1.1.0.bb | 15 - .../websocketpp/websocketpp_0.8.1.bb | 15 - .../recipes-support/curl/curl_7.65.3.bb | 26 - .../recipes-support/sqlite/sqlite3_%.bbappend | 7 - .../classes/hostnativepackage.bbclass | 18 - .../classes/python3native.bbclass | 17 - builder/meta-aac-ubuntu/conf/layer.conf | 28 - .../recipes-native/db/db-native.bb | 5 - .../recipes-native/expat/expat-native.bb | 1 - .../libarchive/libarchive-native.bb | 4 - .../recipes-native/popt/popt-native.bb | 1 - .../recipes-native/zlib/zlib-native.bb | 3 - builder/meta-aac/README.md | 20 - builder/meta-aac/classes/aac-module.bbclass | 49 - builder/meta-aac/classes/devlibsonly.bbclass | 2 - builder/meta-aac/classes/unittests.bbclass | 5 - builder/meta-aac/conf/layer.conf | 25 - builder/meta-aac/custom-licenses/ASL-1.0 | 96 - builder/meta-aac/lib/aac/__init__.py | 59 - .../apl-core-library/apl-core-library_git.bb | 29 - ...1-Auto-SDK-Changes-for-v1.22-AVS-SDK.patch | 7909 ------ .../avs-device-sdk/avs-device-sdk.inc | 84 - .../avs-device-sdk/avs-device-sdk_1.22.0.bb | 10 - ...-Smart-Screen-SDK-for-Alexa-Auto-SDK.patch | 40 - ...ble-SmartScreenCapabilityAgents-test.patch | 55 - .../smart-screen-sdk/smart-screen-sdk_git.bb | 24 - .../nghttp2/nghttp2_1.39.1.bb | 15 - .../googletest/googletest_1.8.0.bb | 29 - ...ude-descriptor.cc-when-building-libp.patch | 28 - .../0001-protobuf-fix-configure-error.patch | 33 - .../protobuf/protobuf_3.9.0.bb | 29 - .../libopus/libopus_1.3.1.bb | 15 - .../recipes-support/curl/curl_%.bbappend | 14 - .../recipes-wakeword/snowboy/snowboy_1.3.0.bb | 30 - builder/pylib/build_cmd.py | 212 + builder/pylib/clean_cmd.py | 16 + builder/pylib/common.py | 480 + builder/pylib/configure_cmd.py | 13 + builder/pylib/imports_cmd.py | 49 + builder/scripts/Dockerfile | 67 - builder/scripts/agreement.sh | 30 - builder/scripts/common.sh | 23 - builder/scripts/gen-version.sh | 68 - builder/scripts/run-aacs-android.sh | 245 - builder/scripts/run-bitbake.sh | 381 - builder/scripts/run-builder.sh | 441 - builder/scripts/run-docker.sh | 64 - builder/scripts/run-gradle.sh | 210 - builder/scripts/setup-android-toolchain.sh | 108 - builder/scripts/version | 2 - conan/config/profiles/aac-android | 13 + conan/config/profiles/aac-linux | 6 + conan/config/profiles/aac-macos | 5 + conan/config/profiles/aac-mingw | 25 + conan/config/profiles/aac-poky | 12 + conan/config/profiles/aac-qnx | 15 + conan/config/remotes.txt | 1 + conan/docker/aac-ubuntu-bionic/Dockerfile | 30 + conan/docker/aac-ubuntu-focal/Dockerfile | 20 + conan/recipes/aac-sdk-tools/CMakeLists.txt | 61 + conan/recipes/aac-sdk-tools/build.gradle | 66 + .../recipes/aac-sdk-tools}/certs/09789157.0 | 0 .../recipes/aac-sdk-tools}/certs/3513523f.0 | 0 .../recipes/aac-sdk-tools}/certs/6d41d539.0 | 0 .../recipes/aac-sdk-tools}/certs/85cf5865.0 | 0 .../recipes/aac-sdk-tools}/certs/8cb5ee0f.0 | 0 .../recipes/aac-sdk-tools}/certs/b204d74a.0 | 0 .../recipes/aac-sdk-tools}/certs/ce5e74ef.0 | 0 .../recipes/aac-sdk-tools}/certs/de6d66f3.0 | 0 .../recipes/aac-sdk-tools}/certs/f387163d.0 | 0 .../cmake/001-aac-base-module.cmake | 38 + conan/recipes/aac-sdk-tools/conanfile.py | 375 + .../aac-sdk-tools/gradle/gradle.properties | 21 + .../recipes/aac-sdk-tools/pylib/a2ml_build.py | 62 + .../aac-sdk-tools/pylib/cmake_build.py | 166 + .../recipes/aac-sdk-tools/pylib/ddl_build.py | 8 + .../aac-sdk-tools/pylib/gradle_build.py | 84 + conan/recipes/aac-sdk-tools/pylib/utils.py | 74 + conan/recipes/android-sdk-tools/cmake-wrapper | 39 + .../android-sdk-tools/cmake-wrapper.cmd | 35 + conan/recipes/android-sdk-tools/conanfile.py | 224 + conan/recipes/apl-core/conanfile.py | 60 + conan/recipes/avs-device-sdk/conanfile.py | 104 + ...Auto-SDK-Changes-for-v1.25.0-AVS-SDK.patch | 5053 ++++ conan/recipes/cheetah/conanfile.py | 27 + .../patches/fix_namemapper_warning.patch | 22 + conan/recipes/faad2/conanfile.py | 51 + conan/recipes/glib-networking/conanfile.py | 71 + conan/recipes/glib/conandata.yml | 61 + conan/recipes/glib/conanfile.py | 299 + conan/recipes/gradle/conanfile.py | 55 + conan/recipes/gst-plugins-bad/conandata.yml | 4 + conan/recipes/gst-plugins-bad/conanfile.py | 121 + .../0001-Remove-unnecessary-stuff.patch | 28 + conan/recipes/gst-plugins-base/conandata.yml | 4 + conan/recipes/gst-plugins-base/conanfile.py | 152 + conan/recipes/gst-plugins-good/conandata.yml | 4 + conan/recipes/gst-plugins-good/conanfile.py | 121 + ...ifile-test-splitmuxpartreader-link-e.patch | 31 + ...FAULT_SSL_STRICT-to-FALSE-by-default.patch | 25 + conan/recipes/gstreamer/conandata.yml | 4 + conan/recipes/gstreamer/conanfile.py | 147 + conan/recipes/libcurl/all/CMakeLists.txt | 8 + conan/recipes/libcurl/all/conandata.yml | 50 + conan/recipes/libcurl/all/conanfile.py | 548 + conan/recipes/libcurl/all/lib_Makefile_add.am | 24 + ...H2.cmake-add-libssh2-as-possible-nam.patch | 16 + .../002-add-missing-file-FindZstd.patch | 72 + ...-Fix-linker-error-of-_getpid-for-QNX.patch | 25 + conan/recipes/libcurl/config.yml | 23 + conan/recipes/libnghttp2/all/CMakeLists.txt | 7 + conan/recipes/libnghttp2/all/conandata.yml | 32 + conan/recipes/libnghttp2/all/conanfile.py | 182 + .../fix-addNghttp2IncludesPathCMake.patch | 11 + .../all/patches/fix-findJemalloc.cmake | 14 + .../all/patches/fix-findLibevent.cmake | 11 + .../nghttp_static_include_directories.patch | 13 + ...tp_static_include_directories_1.42.0.patch | 12 + conan/recipes/libnghttp2/config.yml | 7 + conan/recipes/libsoup/conanfile.py | 68 + conan/recipes/poky-sdk/conandata.yml | 9 + conan/recipes/poky-sdk/conanfile.py | 173 + conan/recipes/pyyaml/conanfile.py | 22 + conan/recipes/qnx7-sdp/conanfile.py | 104 + conan/recipes/qnx7-sdp/openssl/conanfile.py | 106 + .../qnx7-sdp/qnx7_toolchain_armv8.cmake | 13 + .../qnx7-sdp/qnx7_toolchain_x86_64.cmake | 13 + conan/recipes/smart-screen-sdk/conanfile.py | 68 + ...-Smart-Screen-SDK-for-Alexa-Auto-SDK.patch | 54 + ...ble-SmartScreenCapabilityAgents-test.patch | 44 + .../0003-Disable-APLClient-dependency.patch | 24 +- .../patches/0004-Disable-GUI.patch | 25 + .../0005-Template-runtime-version-1.2.patch | 25 + .../0006-Ignore-template-runtime-token.patch | 32 + conan/setup.py | 28 + docs/android/annotated.html | 243 +- ..._1_address_book_configuration-members.html | 86 - ...config_1_1_address_book_configuration.html | 127 - ...n_1_1aace_1_1alexa_1_1_alerts-members.html | 4 +- ...1_1amazon_1_1aace_1_1alexa_1_1_alerts.html | 8 +- ...ace_1_1alexa_1_1_alexa_client-members.html | 4 +- ...zon_1_1aace_1_1alexa_1_1_alexa_client.html | 8 +- ...ce_1_1alexa_1_1_alexa_speaker-members.html | 4 +- ...on_1_1aace_1_1alexa_1_1_alexa_speaker.html | 8 +- ...ace_1_1alexa_1_1_audio_player-members.html | 4 +- ...zon_1_1aace_1_1alexa_1_1_audio_player.html | 8 +- ...ce_1_1alexa_1_1_auth_provider-members.html | 4 +- ...on_1_1aace_1_1alexa_1_1_auth_provider.html | 15 +- ...ace_1_1alexa_1_1_device_setup-members.html | 4 +- ...zon_1_1aace_1_1alexa_1_1_device_setup.html | 8 +- ...e_1_1alexa_1_1_do_not_disturb-members.html | 4 +- ...n_1_1aace_1_1alexa_1_1_do_not_disturb.html | 8 +- ...lexa_1_1_equalizer_controller-members.html | 4 +- ...ace_1_1alexa_1_1_equalizer_controller.html | 8 +- ...xa_1_1_external_media_adapter-members.html | 4 +- ...e_1_1alexa_1_1_external_media_adapter.html | 8 +- ...ce_1_1alexa_1_1_global_preset-members.html | 4 +- ...on_1_1aace_1_1alexa_1_1_global_preset.html | 9 +- ...1alexa_1_1_local_media_source-members.html | 4 +- ...1aace_1_1alexa_1_1_local_media_source.html | 18 +- ..._1_1_media_playback_requestor-members.html | 88 + ...1_1alexa_1_1_media_playback_requestor.html | 178 + ...ce_1_1alexa_1_1_notifications-members.html | 4 +- ...on_1_1aace_1_1alexa_1_1_notifications.html | 8 +- ...alexa_1_1_playback_controller-members.html | 4 +- ...aace_1_1alexa_1_1_playback_controller.html | 8 +- ..._1alexa_1_1_speech_recognizer-members.html | 4 +- ..._1aace_1_1alexa_1_1_speech_recognizer.html | 8 +- ...1alexa_1_1_speech_synthesizer-members.html | 4 +- ...1aace_1_1alexa_1_1_speech_synthesizer.html | 8 +- ...1_1alexa_1_1_template_runtime-members.html | 4 +- ...1_1aace_1_1alexa_1_1_template_runtime.html | 8 +- ...onfig_1_1_alexa_configuration-members.html | 14 +- ...exa_1_1config_1_1_alexa_configuration.html | 114 +- ...azon_1_1aace_1_1apl_1_1_a_p_l-members.html | 6 +- ...om_1_1amazon_1_1aace_1_1apl_1_1_a_p_l.html | 93 +- ...onfig_1_1_a_p_l_configuration-members.html | 4 +- ...apl_1_1config_1_1_a_p_l_configuration.html | 4 +- ...udio_1_1_audio_input_provider-members.html | 4 +- ...ace_1_1audio_1_1_audio_input_provider.html | 8 +- ...ace_1_1audio_1_1_audio_output-members.html | 29 +- ...zon_1_1aace_1_1audio_1_1_audio_output.html | 66 +- ...dio_1_1_audio_output_provider-members.html | 4 +- ...ce_1_1audio_1_1_audio_output_provider.html | 8 +- ...thorization_1_1_authorization-members.html | 4 +- ...ce_1_1authorization_1_1_authorization.html | 8 +- ..._1car_control_1_1_car_control-members.html | 4 +- ..._1aace_1_1car_control_1_1_car_control.html | 8 +- ...1_1_car_control_configuration-members.html | 4 +- ...control_1_1_car_control_configuration.html | 6 +- ...trol_configuration_1_1_action-members.html | 4 +- ..._car_control_configuration_1_1_action.html | 4 +- ...azon_1_1aace_1_1cbl_1_1_c_b_l-members.html | 4 +- ...om_1_1amazon_1_1aace_1_1cbl_1_1_c_b_l.html | 23 +- ...onfig_1_1_c_b_l_configuration-members.html | 4 +- ...cbl_1_1config_1_1_c_b_l_configuration.html | 6 +- ...tivity_1_1_alexa_connectivity-members.html | 91 + ..._1connectivity_1_1_alexa_connectivity.html | 331 + ...on_1_1aace_1_1core_1_1_engine-members.html | 13 +- ..._1_1amazon_1_1aace_1_1core_1_1_engine.html | 70 +- ..._1core_1_1_platform_interface-members.html | 4 +- ..._1aace_1_1core_1_1_platform_interface.html | 4 +- ...nfig_1_1_engine_configuration-members.html | 4 +- ...re_1_1config_1_1_engine_configuration.html | 4 +- ...stom_domain_1_1_custom_domain-members.html | 90 + ...ce_1_1custom_domain_1_1_custom_domain.html | 393 + ...device_usage_1_1_device_usage-members.html | 4 +- ...aace_1_1device_usage_1_1_device_usage.html | 6 +- ...aace_1_1location_1_1_location-members.html | 4 +- ...azon_1_1aace_1_1location_1_1_location.html | 4 +- ...ocation_1_1_location_provider-members.html | 4 +- ...ace_1_1location_1_1_location_provider.html | 8 +- ..._1_1aace_1_1logger_1_1_logger-members.html | 4 +- ..._1amazon_1_1aace_1_1logger_1_1_logger.html | 8 +- ...nfig_1_1_logger_configuration-members.html | 4 +- ...er_1_1config_1_1_logger_configuration.html | 4 +- ..._1_1navigation_1_1_navigation-members.html | 4 +- ..._1_1aace_1_1navigation_1_1_navigation.html | 8 +- ..._1_1_navigation_configuration-members.html | 4 +- ..._1config_1_1_navigation_configuration.html | 4 +- ...ork_1_1_network_info_provider-members.html | 4 +- ..._1_1network_1_1_network_info_provider.html | 8 +- ...rol_1_1_phone_call_controller-members.html | 101 - ...honecontrol_1_1_phone_call_controller.html | 752 - ..._manager_1_1_property_manager-members.html | 4 +- ...property_manager_1_1_property_manager.html | 8 +- ...fig_1_1_storage_configuration-members.html | 4 +- ...e_1_1config_1_1_storage_configuration.html | 4 +- ..._to_speech_1_1_text_to_speech-members.html | 90 + ..._1_1text_to_speech_1_1_text_to_speech.html | 332 + ...fig_1_1_vehicle_configuration-members.html | 4 +- ...e_1_1config_1_1_vehicle_configuration.html | 4 +- ...android_1_1_example_unit_test-members.html | 85 - ..._1_1maccandroid_1_1_example_unit_test.html | 87 - ...id_1_1_m_a_c_c_android_client-members.html | 89 - ...accandroid_1_1_m_a_c_c_android_client.html | 190 - ...odel_1_1_player_playback_info-members.html | 85 - ...oid_1_1model_1_1_player_playback_info.html | 86 - docs/android/classes.html | 43 +- docs/android/deprecated.html | 116 +- ...ss_book_1_1_address_book_type-members.html | 87 - ..._1_address_book_1_1_address_book_type.html | 126 - ...xa_1_1_alerts_1_1_alert_state-members.html | 4 +- ...e_1_1alexa_1_1_alerts_1_1_alert_state.html | 4 +- ...1_alexa_client_1_1_auth_error-members.html | 4 +- ...alexa_1_1_alexa_client_1_1_auth_error.html | 4 +- ...1_alexa_client_1_1_auth_state-members.html | 4 +- ...alexa_1_1_alexa_client_1_1_auth_state.html | 4 +- ...1_1_connection_changed_reason-members.html | 4 +- ..._client_1_1_connection_changed_reason.html | 4 +- ..._client_1_1_connection_status-members.html | 4 +- ..._1_alexa_client_1_1_connection_status.html | 4 +- ...alexa_client_1_1_dialog_state-members.html | 4 +- ...exa_1_1_alexa_client_1_1_dialog_state.html | 4 +- ...lexa_speaker_1_1_speaker_type-members.html | 4 +- ...xa_1_1_alexa_speaker_1_1_speaker_type.html | 4 +- ...io_player_1_1_player_activity-members.html | 4 +- ..._1_1_audio_player_1_1_player_activity.html | 4 +- ..._auth_provider_1_1_auth_error-members.html | 4 +- ...lexa_1_1_auth_provider_1_1_auth_error.html | 4 +- ..._auth_provider_1_1_auth_state-members.html | 4 +- ...lexa_1_1_auth_provider_1_1_auth_state.html | 4 +- ..._device_setup_1_1_status_code-members.html | 4 +- ...lexa_1_1_device_setup_1_1_status_code.html | 4 +- ...controller_1_1_equalizer_band-members.html | 4 +- ...ualizer_controller_1_1_equalizer_band.html | 4 +- ...l_media_adapter_1_1_favorites-members.html | 4 +- ..._external_media_adapter_1_1_favorites.html | 4 +- ..._media_adapter_1_1_media_type-members.html | 4 +- ...external_media_adapter_1_1_media_type.html | 4 +- ..._media_adapter_1_1_navigation-members.html | 4 +- ...external_media_adapter_1_1_navigation.html | 4 +- ...adapter_1_1_play_control_type-members.html | 4 +- ...l_media_adapter_1_1_play_control_type.html | 4 +- ..._supported_playback_operation-members.html | 4 +- ...pter_1_1_supported_playback_operation.html | 4 +- ...a_source_1_1_content_selector-members.html | 4 +- ...cal_media_source_1_1_content_selector.html | 4 +- ...al_media_source_1_1_favorites-members.html | 4 +- ..._1_1_local_media_source_1_1_favorites.html | 4 +- ...l_media_source_1_1_media_type-members.html | 4 +- ...1_1_local_media_source_1_1_media_type.html | 4 +- ..._source_1_1_play_control_type-members.html | 4 +- ...al_media_source_1_1_play_control_type.html | 4 +- ...local_media_source_1_1_source-members.html | 4 +- ...exa_1_1_local_media_source_1_1_source.html | 4 +- ..._supported_playback_operation-members.html | 4 +- ...urce_1_1_supported_playback_operation.html | 4 +- ...questor_1_1_invocation_reason-members.html | 87 + ...yback_requestor_1_1_invocation_reason.html | 126 + ...media_playback_request_status-members.html | 89 + ...tor_1_1_media_playback_request_status.html | 160 + ...fications_1_1_indicator_state-members.html | 4 +- ...1_1_notifications_1_1_indicator_state.html | 4 +- ...ontroller_1_1_playback_button-members.html | 4 +- ...ayback_controller_1_1_playback_button.html | 4 +- ...ontroller_1_1_playback_toggle-members.html | 4 +- ...ayback_controller_1_1_playback_toggle.html | 4 +- ...eech_recognizer_1_1_initiator-members.html | 4 +- ...a_1_1_speech_recognizer_1_1_initiator.html | 4 +- ...plate_runtime_1_1_focus_state-members.html | 4 +- ..._1_1_template_runtime_1_1_focus_state.html | 4 +- ...e_runtime_1_1_player_activity-members.html | 4 +- ..._template_runtime_1_1_player_activity.html | 4 +- ..._1_1_a_p_l_1_1_activity_event-members.html | 4 +- ...e_1_1apl_1_1_a_p_l_1_1_activity_event.html | 4 +- ...1_1_audio_format_1_1_encoding-members.html | 4 +- ..._1audio_1_1_audio_format_1_1_encoding.html | 4 +- ...provider_1_1_audio_input_type-members.html | 4 +- ...o_input_provider_1_1_audio_input_type.html | 4 +- ...audio_output_1_1_focus_action-members.html | 87 + ...dio_1_1_audio_output_1_1_focus_action.html | 126 + ..._audio_output_1_1_media_error-members.html | 4 +- ...udio_1_1_audio_output_1_1_media_error.html | 4 +- ..._audio_output_1_1_media_state-members.html | 4 +- ...udio_1_1_audio_output_1_1_media_state.html | 4 +- ..._audio_output_1_1_muted_state-members.html | 4 +- ...udio_1_1_audio_output_1_1_muted_state.html | 4 +- ...rovider_1_1_audio_output_type-members.html | 4 +- ...output_provider_1_1_audio_output_type.html | 4 +- ...1_1_audio_stream_1_1_encoding-members.html | 4 +- ..._1audio_1_1_audio_stream_1_1_encoding.html | 4 +- ...ation_1_1_authorization_state-members.html | 4 +- ...authorization_1_1_authorization_state.html | 4 +- ...t_server_1_1_connection_state-members.html | 85 + ...1_g_a_t_t_server_1_1_connection_state.html | 87 + ...cbl_1_1_c_b_l_1_1_c_b_l_state-members.html | 4 +- ...aace_1_1cbl_1_1_c_b_l_1_1_c_b_l_state.html | 4 +- ..._1_c_b_l_state_changed_reason-members.html | 4 +- ..._c_b_l_1_1_c_b_l_state_changed_reason.html | 4 +- ..._connectivity_1_1_status_code-members.html | 87 + ..._1_alexa_connectivity_1_1_status_code.html | 126 + ...e_1_1_message_stream_1_1_mode-members.html | 85 + ...e_1_1core_1_1_message_stream_1_1_mode.html | 89 + ...custom_domain_1_1_result_type-members.html | 89 + ...ain_1_1_custom_domain_1_1_result_type.html | 160 + ...r_1_1_location_service_access-members.html | 4 +- ..._provider_1_1_location_service_access.html | 4 +- ..._1logger_1_1_logger_1_1_level-members.html | 4 +- ..._1aace_1_1logger_1_1_logger_1_1_level.html | 4 +- ...o_provider_1_1_network_status-members.html | 4 +- ...work_info_provider_1_1_network_status.html | 4 +- ...all_controller_1_1_call_error-members.html | 90 - ..._phone_call_controller_1_1_call_error.html | 178 - ...all_controller_1_1_call_state-members.html | 91 - ..._phone_call_controller_1_1_call_state.html | 203 - ...device_configuration_property-members.html | 86 - ...calling_device_configuration_property.html | 109 - ...ntroller_1_1_connection_state-members.html | 87 - ..._call_controller_1_1_connection_state.html | 127 - ..._controller_1_1_d_t_m_f_error-members.html | 87 - ...one_call_controller_1_1_d_t_m_f_error.html | 127 - ...ty_manager_1_1_property_state-members.html | 4 +- ...1_property_manager_1_1_property_state.html | 4 +- ...ion_1_1_vehicle_property_type-members.html | 4 +- ...nfiguration_1_1_vehicle_property_type.html | 4 +- docs/android/functions.html | 206 +- docs/android/functions_func.html | 142 +- docs/android/functions_vars.html | 80 +- docs/android/hierarchy.html | 196 +- docs/android/index.html | 4 +- docs/android/menudata.js | 1 + docs/android/pages.html | 4 +- docs/android/search/all_0.js | 6 +- docs/android/search/all_1.js | 1 - docs/android/search/all_10.js | 1 + docs/android/search/all_11.js | 3 + docs/android/search/all_2.js | 28 +- docs/android/search/all_3.js | 10 +- docs/android/search/all_4.js | 6 +- docs/android/search/all_5.js | 7 +- docs/android/search/all_6.js | 7 +- docs/android/search/all_7.js | 2 +- docs/android/search/all_8.js | 7 +- docs/android/search/all_a.js | 6 +- docs/android/search/all_b.js | 5 +- docs/android/search/all_c.js | 4 +- docs/android/search/all_d.js | 9 +- docs/android/search/all_e.js | 10 +- docs/android/search/all_f.js | 19 +- docs/android/search/classes_0.js | 3 +- docs/android/search/classes_1.js | 8 +- docs/android/search/classes_2.js | 3 +- docs/android/search/classes_3.js | 3 +- docs/android/search/classes_4.js | 3 +- docs/android/search/classes_6.js | 3 +- docs/android/search/classes_8.js | 4 +- docs/android/search/classes_9.js | 2 +- docs/android/search/classes_a.js | 4 +- docs/android/search/classes_b.js | 8 +- docs/android/search/classes_c.js | 8 +- docs/android/search/classes_d.js | 4 +- docs/android/search/classes_e.html | 26 + docs/android/search/classes_e.js | 5 + docs/android/search/functions_0.js | 1 - docs/android/search/functions_10.js | 3 +- docs/android/search/functions_11.js | 3 +- docs/android/search/functions_12.html | 26 + docs/android/search/functions_12.js | 4 + docs/android/search/functions_2.js | 15 +- docs/android/search/functions_3.js | 2 - docs/android/search/functions_5.js | 7 +- docs/android/search/functions_6.js | 2 +- docs/android/search/functions_7.js | 1 - docs/android/search/functions_9.js | 2 + docs/android/search/functions_b.js | 1 - docs/android/search/functions_c.js | 3 + docs/android/search/functions_d.js | 5 +- docs/android/search/functions_e.js | 13 +- docs/android/search/searchdata.js | 4 +- docs/android/search/variables_0.js | 4 +- docs/android/search/variables_1.js | 3 +- docs/android/search/variables_11.js | 2 + docs/android/search/variables_2.js | 5 +- docs/android/search/variables_3.js | 7 +- docs/android/search/variables_4.js | 5 +- docs/android/search/variables_5.js | 4 +- docs/android/search/variables_8.js | 5 +- docs/android/search/variables_b.js | 4 - docs/android/search/variables_c.js | 3 +- docs/android/search/variables_e.js | 2 + docs/android/search/variables_f.js | 2 +- docs/cpp/_a_p_l_8h_source.html | 8 +- docs/cpp/_a_p_l_configuration_8h_source.html | 4 +- .../_a_p_l_engine_interface_8h_source.html | 6 +- docs/cpp/_address_book_8h_source.html | 12 +- ..._address_book_configuration_8h_source.html | 4 +- ...dress_book_engine_interface_8h_source.html | 6 +- docs/cpp/_alerts_8h_source.html | 10 +- docs/cpp/_alexa_client_8h_source.html | 24 +- docs/cpp/_alexa_configuration_8h_source.html | 19 +- docs/cpp/_alexa_connectivity_8h_source.html | 90 + ...nnectivity_engine_interface_8h_source.html | 83 + .../_alexa_engine_interfaces_8h_source.html | 62 +- docs/cpp/_alexa_properties_8h_source.html | 4 +- docs/cpp/_alexa_speaker_8h_source.html | 10 +- .../_audio_engine_interfaces_8h_source.html | 6 +- docs/cpp/_audio_format_8h_source.html | 6 +- docs/cpp/_audio_input_8h_source.html | 4 +- docs/cpp/_audio_input_provider_8h_source.html | 7 +- docs/cpp/_audio_output_8h_source.html | 12 +- .../cpp/_audio_output_provider_8h_source.html | 7 +- docs/cpp/_audio_player_8h_source.html | 12 +- docs/cpp/_audio_stream_8h_source.html | 4 +- docs/cpp/_auth_provider_8h_source.html | 14 +- docs/cpp/_authorization_8h_source.html | 8 +- ...horization_engine_interface_8h_source.html | 4 +- ...bluetooth_engine_interfaces_8h_source.html | 83 + docs/cpp/_bluetooth_provider_8h_source.html | 88 + .../_bluetooth_server_socket_8h_source.html | 83 + docs/cpp/_bluetooth_socket_8h_source.html | 83 + docs/cpp/_byte_array_8h_source.html | 83 + docs/cpp/_c_b_l_8h_source.html | 12 +- docs/cpp/_c_b_l_configuration_8h_source.html | 4 +- .../_c_b_l_engine_interface_8h_source.html | 6 +- docs/cpp/_car_control_8h_source.html | 8 +- docs/cpp/_car_control_assets_8h_source.html | 4 +- .../_car_control_configuration_8h_source.html | 4 +- docs/cpp/_core_properties_8h_source.html | 4 +- docs/cpp/_device_setup_8h_source.html | 12 +- docs/cpp/_device_usage_8h_source.html | 4 +- ...ice_usage_engine_interfaces_8h_source.html | 6 +- docs/cpp/_do_not_disturb_8h_source.html | 8 +- docs/cpp/_engine_8h_source.html | 9 +- docs/cpp/_engine_configuration_8h_source.html | 4 +- docs/cpp/_equalizer_controller_8h_source.html | 14 +- .../_external_media_adapter_8h_source.html | 161 +- docs/cpp/_focus_state_8h_source.html | 4 +- docs/cpp/_g_a_t_t_server_8h_source.html | 83 + docs/cpp/_global_preset_8h_source.html | 6 +- docs/cpp/_local_media_source_8h_source.html | 94 +- docs/cpp/_location_8h_source.html | 4 +- docs/cpp/_location_provider_8h_source.html | 10 +- ...n_provider_engine_interface_8h_source.html | 8 +- docs/cpp/_logger_8h_source.html | 8 +- docs/cpp/_logger_configuration_8h_source.html | 6 +- .../_logger_engine_interfaces_8h_source.html | 8 +- .../_media_playback_requestor_8h_source.html | 95 + docs/cpp/_message_broker_8h_source.html | 87 + docs/cpp/_message_stream_8h_source.html | 83 + docs/cpp/_metrics_uploader_8h_source.html | 12 +- docs/cpp/_navigation_8h_source.html | 6 +- .../_navigation_configuration_8h_source.html | 4 +- ...avigation_engine_interfaces_8h_source.html | 6 +- .../_network_engine_interfaces_8h_source.html | 8 +- .../cpp/_network_info_provider_8h_source.html | 10 +- docs/cpp/_network_properties_8h_source.html | 6 +- docs/cpp/_notifications_8h_source.html | 10 +- .../cpp/_phone_call_controller_8h_source.html | 18 +- ...ontroller_engine_interfaces_8h_source.html | 16 +- docs/cpp/_platform_interface_8h_source.html | 4 +- docs/cpp/_playback_controller_8h_source.html | 10 +- docs/cpp/_player_activity_8h_source.html | 4 +- docs/cpp/_property_manager_8h_source.html | 8 +- ...ty_manager_engine_interface_8h_source.html | 6 +- docs/cpp/_speech_recognizer_8h_source.html | 10 +- docs/cpp/_speech_synthesizer_8h_source.html | 8 +- .../cpp/_storage_configuration_8h_source.html | 4 +- docs/cpp/_template_runtime_8h_source.html | 6 +- docs/cpp/_text_to_speech_8h_source.html | 90 + ..._to_speech_engine_interface_8h_source.html | 83 + .../cpp/_vehicle_configuration_8h_source.html | 4 +- docs/cpp/_vehicle_properties_8h_source.html | 4 +- docs/cpp/annotated.html | 208 +- ...address_book_1_1_address_book-members.html | 88 + ...aace_1_1address_book_1_1_address_book.html | 220 + ..._address_book_entries_factory-members.html | 6 +- ...ok_1_1_i_address_book_entries_factory.html | 18 +- ..._1_address_book_configuration-members.html | 4 +- ...config_1_1_address_book_configuration.html | 4 +- ...classaace_1_1alexa_1_1_alerts-members.html | 4 +- docs/cpp/classaace_1_1alexa_1_1_alerts.html | 8 +- ...a_1_1_alerts_engine_interface-members.html | 4 +- ..._1_1alexa_1_1_alerts_engine_interface.html | 4 +- ...ace_1_1alexa_1_1_alexa_client-members.html | 4 +- .../classaace_1_1alexa_1_1_alexa_client.html | 8 +- ...alexa_client_engine_interface-members.html | 4 +- ...exa_1_1_alexa_client_engine_interface.html | 4 +- ...ce_1_1alexa_1_1_alexa_speaker-members.html | 4 +- .../classaace_1_1alexa_1_1_alexa_speaker.html | 8 +- ...lexa_speaker_engine_interface-members.html | 4 +- ...xa_1_1_alexa_speaker_engine_interface.html | 4 +- ...ace_1_1alexa_1_1_audio_player-members.html | 4 +- .../classaace_1_1alexa_1_1_audio_player.html | 8 +- ...audio_player_engine_interface-members.html | 4 +- ...exa_1_1_audio_player_engine_interface.html | 4 +- ...ce_1_1alexa_1_1_auth_provider-members.html | 4 +- .../classaace_1_1alexa_1_1_auth_provider.html | 19 +- ...uth_provider_engine_interface-members.html | 4 +- ...xa_1_1_auth_provider_engine_interface.html | 4 +- ...ace_1_1alexa_1_1_device_setup-members.html | 4 +- .../classaace_1_1alexa_1_1_device_setup.html | 8 +- ...device_setup_engine_interface-members.html | 4 +- ...exa_1_1_device_setup_engine_interface.html | 4 +- ...e_1_1alexa_1_1_do_not_disturb-members.html | 4 +- ...classaace_1_1alexa_1_1_do_not_disturb.html | 8 +- ..._not_disturb_engine_interface-members.html | 4 +- ...a_1_1_do_not_disturb_engine_interface.html | 4 +- ...lexa_1_1_equalizer_controller-members.html | 4 +- ...ace_1_1alexa_1_1_equalizer_controller.html | 8 +- ...r_controller_engine_interface-members.html | 4 +- ...equalizer_controller_engine_interface.html | 4 +- ...xa_1_1_external_media_adapter-members.html | 109 + ...e_1_1alexa_1_1_external_media_adapter.html | 1267 + ...er_1_1_authorized_player_info-members.html | 6 +- ...ia_adapter_1_1_authorized_player_info.html | 6 +- ..._external_media_adapter_state-members.html | 6 +- ...pter_1_1_external_media_adapter_state.html | 6 +- ...ia_adapter_1_1_playback_state-members.html | 6 +- ...rnal_media_adapter_1_1_playback_state.html | 12 +- ...dia_adapter_1_1_session_state-members.html | 6 +- ...ernal_media_adapter_1_1_session_state.html | 6 +- ...edia_adapter_engine_interface-members.html | 4 +- ...ternal_media_adapter_engine_interface.html | 4 +- ...ce_1_1_discovered_player_info-members.html | 4 +- ..._interface_1_1_discovered_player_info.html | 4 +- ...ce_1_1alexa_1_1_global_preset-members.html | 4 +- .../classaace_1_1alexa_1_1_global_preset.html | 9 +- ...1alexa_1_1_local_media_source-members.html | 4 +- ...saace_1_1alexa_1_1_local_media_source.html | 20 +- ..._1_1_local_media_source_state-members.html | 4 +- ...a_source_1_1_local_media_source_state.html | 4 +- ...dia_source_1_1_playback_state-members.html | 4 +- ...local_media_source_1_1_playback_state.html | 10 +- ...edia_source_1_1_session_state-members.html | 4 +- ..._local_media_source_1_1_session_state.html | 4 +- ...media_source_engine_interface-members.html | 4 +- ...1_local_media_source_engine_interface.html | 4 +- ..._1_1_media_playback_requestor-members.html | 87 + ...1_1alexa_1_1_media_playback_requestor.html | 159 + ...ck_requestor_engine_interface-members.html | 87 + ...a_playback_requestor_engine_interface.html | 173 + ...ce_1_1alexa_1_1_notifications-members.html | 4 +- .../classaace_1_1alexa_1_1_notifications.html | 8 +- ...alexa_1_1_playback_controller-members.html | 4 +- ...aace_1_1alexa_1_1_playback_controller.html | 8 +- ...k_controller_engine_interface-members.html | 4 +- ..._playback_controller_engine_interface.html | 4 +- ..._1alexa_1_1_speech_recognizer-members.html | 4 +- ...ssaace_1_1alexa_1_1_speech_recognizer.html | 8 +- ...h_recognizer_engine_interface-members.html | 4 +- ..._1_speech_recognizer_engine_interface.html | 4 +- ...1alexa_1_1_speech_synthesizer-members.html | 4 +- ...saace_1_1alexa_1_1_speech_synthesizer.html | 8 +- ...1_1alexa_1_1_template_runtime-members.html | 4 +- ...assaace_1_1alexa_1_1_template_runtime.html | 8 +- ...late_runtime_engine_interface-members.html | 4 +- ...1_1_template_runtime_engine_interface.html | 4 +- ...onfig_1_1_alexa_configuration-members.html | 33 +- ...exa_1_1config_1_1_alexa_configuration.html | 64 +- .../classaace_1_1apl_1_1_a_p_l-members.html | 6 +- docs/cpp/classaace_1_1apl_1_1_a_p_l.html | 104 +- ...onfig_1_1_a_p_l_configuration-members.html | 4 +- ...apl_1_1config_1_1_a_p_l_configuration.html | 4 +- ...udio_1_1_audio_input_provider-members.html | 85 + ...ace_1_1audio_1_1_audio_input_provider.html | 87 + ...ace_1_1audio_1_1_audio_output-members.html | 37 +- .../classaace_1_1audio_1_1_audio_output.html | 132 +- ...dio_1_1_audio_output_provider-members.html | 85 + ...ce_1_1audio_1_1_audio_output_provider.html | 87 + ...dio_1_1_audio_stream_property-members.html | 4 +- ...ce_1_1audio_1_1_audio_stream_property.html | 4 +- ...thorization_1_1_authorization-members.html | 4 +- ...ce_1_1authorization_1_1_authorization.html | 8 +- ...uthorization_engine_interface-members.html | 4 +- ...on_1_1_authorization_engine_interface.html | 4 +- ...etooth_1_1_bluetooth_provider-members.html | 88 + ...e_1_1bluetooth_1_1_bluetooth_provider.html | 204 + ..._1car_control_1_1_car_control-members.html | 4 +- ...ssaace_1_1car_control_1_1_car_control.html | 8 +- ...1_1_car_control_configuration-members.html | 4 +- ...1config_1_1_car_control_configuration.html | 6 +- .../classaace_1_1cbl_1_1_c_b_l-members.html | 4 +- docs/cpp/classaace_1_1cbl_1_1_c_b_l.html | 27 +- ...onfig_1_1_c_b_l_configuration-members.html | 4 +- ...cbl_1_1config_1_1_c_b_l_configuration.html | 6 +- ...tivity_1_1_alexa_connectivity-members.html | 91 + ..._1connectivity_1_1_alexa_connectivity.html | 324 + .../classaace_1_1core_1_1_engine-members.html | 15 +- docs/cpp/classaace_1_1core_1_1_engine.html | 32 +- ...ce_1_1core_1_1_message_broker-members.html | 88 + .../classaace_1_1core_1_1_message_broker.html | 226 + ..._1core_1_1_platform_interface-members.html | 4 +- ...ssaace_1_1core_1_1_platform_interface.html | 4 +- ...config_1_1_configuration_file-members.html | 4 +- ...core_1_1config_1_1_configuration_file.html | 4 +- ...nfig_1_1_engine_configuration-members.html | 4 +- ...re_1_1config_1_1_engine_configuration.html | 4 +- ...nfig_1_1_stream_configuration-members.html | 4 +- ...re_1_1config_1_1_stream_configuration.html | 4 +- ...device_usage_1_1_device_usage-members.html | 4 +- ...aace_1_1device_usage_1_1_device_usage.html | 6 +- ...device_usage_engine_interface-members.html | 4 +- ...age_1_1_device_usage_engine_interface.html | 4 +- ...aace_1_1location_1_1_location-members.html | 4 +- .../classaace_1_1location_1_1_location.html | 4 +- ...ocation_1_1_location_provider-members.html | 4 +- ...ace_1_1location_1_1_location_provider.html | 8 +- ...ion_provider_engine_interface-members.html | 4 +- ..._1_location_provider_engine_interface.html | 4 +- ...lassaace_1_1logger_1_1_logger-members.html | 4 +- docs/cpp/classaace_1_1logger_1_1_logger.html | 8 +- ...r_1_1_logger_engine_interface-members.html | 4 +- ...1_1logger_1_1_logger_engine_interface.html | 4 +- ...nfig_1_1_logger_configuration-members.html | 4 +- ...er_1_1config_1_1_logger_configuration.html | 4 +- ...1metrics_1_1_metrics_uploader-members.html | 4 +- ...saace_1_1metrics_1_1_metrics_uploader.html | 8 +- ...etrics_uploader_1_1_datapoint-members.html | 4 +- ...cs_1_1_metrics_uploader_1_1_datapoint.html | 4 +- ..._1_1navigation_1_1_navigation-members.html | 4 +- ...lassaace_1_1navigation_1_1_navigation.html | 8 +- ..._1_1_navigation_configuration-members.html | 4 +- ..._1config_1_1_navigation_configuration.html | 4 +- ...ork_1_1_network_info_provider-members.html | 4 +- ..._1_1network_1_1_network_info_provider.html | 8 +- ...nfo_provider_engine_interface-members.html | 4 +- ...etwork_info_provider_engine_interface.html | 4 +- ...ler_1_1_phone_call_controller-members.html | 4 +- ..._controller_1_1_phone_call_controller.html | 8 +- ...l_controller_engine_interface-members.html | 4 +- ...hone_call_controller_engine_interface.html | 4 +- ..._manager_1_1_property_manager-members.html | 4 +- ...property_manager_1_1_property_manager.html | 8 +- ...fig_1_1_storage_configuration-members.html | 4 +- ...e_1_1config_1_1_storage_configuration.html | 4 +- ..._to_speech_1_1_text_to_speech-members.html | 90 + ..._1_1text_to_speech_1_1_text_to_speech.html | 336 + ...fig_1_1_vehicle_configuration-members.html | 4 +- ...e_1_1config_1_1_vehicle_configuration.html | 4 +- docs/cpp/classes.html | 23 +- docs/cpp/deprecated.html | 130 +- docs/cpp/functions.html | 180 +- docs/cpp/functions_enum.html | 29 +- docs/cpp/functions_func.html | 157 +- docs/cpp/functions_type.html | 10 +- docs/cpp/functions_vars.html | 4 +- docs/cpp/hierarchy.html | 94 +- docs/cpp/index.html | 4 +- docs/cpp/menudata.js | 2 + docs/cpp/namespaceaace.html | 4 +- docs/cpp/namespaceaace_1_1alexa.html | 124 +- ...ce_1_1car_control_1_1config_1_1action.html | 4 +- docs/cpp/namespacemembers.html | 10 +- docs/cpp/namespacemembers_enum.html | 4 +- docs/cpp/namespacemembers_func.html | 10 +- docs/cpp/pages.html | 4 +- docs/cpp/search/all_0.js | 12 +- docs/cpp/search/all_1.js | 1 + docs/cpp/search/all_10.js | 2 + docs/cpp/search/all_11.js | 3 + docs/cpp/search/all_12.js | 2 +- docs/cpp/search/all_2.js | 7 +- docs/cpp/search/all_3.js | 4 +- docs/cpp/search/all_4.js | 7 +- docs/cpp/search/all_5.js | 10 +- docs/cpp/search/all_6.js | 8 +- docs/cpp/search/all_8.js | 2 + docs/cpp/search/all_9.js | 7 +- docs/cpp/search/all_a.js | 13 +- docs/cpp/search/all_b.js | 7 +- docs/cpp/search/all_c.js | 5 +- docs/cpp/search/all_d.js | 23 +- docs/cpp/search/all_e.js | 7 +- docs/cpp/search/all_f.js | 23 +- docs/cpp/search/classes_0.js | 4 + docs/cpp/search/classes_1.js | 6 +- docs/cpp/search/classes_2.js | 13 +- docs/cpp/search/classes_3.js | 14 +- docs/cpp/search/classes_4.js | 8 +- docs/cpp/search/classes_5.js | 2 +- docs/cpp/search/classes_6.js | 10 +- docs/cpp/search/classes_7.js | 10 +- docs/cpp/search/classes_8.js | 9 +- docs/cpp/search/classes_9.js | 12 +- docs/cpp/search/classes_a.js | 13 +- docs/cpp/search/classes_b.js | 8 +- docs/cpp/search/classes_c.js | 4 +- docs/cpp/search/classes_d.html | 26 + docs/cpp/search/classes_d.js | 4 + docs/cpp/search/enums_4.js | 1 + docs/cpp/search/enums_5.js | 3 +- docs/cpp/search/enums_7.js | 2 + docs/cpp/search/enums_8.js | 1 + docs/cpp/search/enums_9.js | 1 + docs/cpp/search/enums_a.js | 3 +- docs/cpp/search/enumvalues_0.js | 5 +- docs/cpp/search/enumvalues_10.js | 1 + docs/cpp/search/enumvalues_11.js | 2 + docs/cpp/search/enumvalues_3.js | 4 +- docs/cpp/search/enumvalues_4.js | 8 +- docs/cpp/search/enumvalues_5.js | 7 +- docs/cpp/search/enumvalues_b.js | 5 +- docs/cpp/search/enumvalues_c.js | 2 +- docs/cpp/search/enumvalues_d.js | 7 +- docs/cpp/search/enumvalues_e.js | 4 +- docs/cpp/search/enumvalues_f.js | 7 +- docs/cpp/search/functions_0.js | 5 +- docs/cpp/search/functions_10.js | 2 +- docs/cpp/search/functions_11.js | 2 +- docs/cpp/search/functions_12.js | 3 +- docs/cpp/search/functions_13.html | 26 + docs/cpp/search/functions_13.js | 5 + docs/cpp/search/functions_2.js | 7 +- docs/cpp/search/functions_5.js | 8 +- docs/cpp/search/functions_7.js | 1 + docs/cpp/search/functions_8.js | 7 +- docs/cpp/search/functions_9.js | 5 +- docs/cpp/search/functions_b.js | 3 +- docs/cpp/search/functions_c.js | 14 +- docs/cpp/search/functions_d.js | 4 + docs/cpp/search/functions_e.js | 11 +- docs/cpp/search/searchdata.js | 6 +- docs/cpp/search/typedefs_4.js | 1 + docs/cpp/search/typedefs_a.js | 2 +- docs/cpp/search/typedefs_b.js | 2 +- docs/cpp/search/typedefs_c.html | 26 + docs/cpp/search/typedefs_c.js | 4 + docs/sdk-docs/404.html | 3955 +++ docs/sdk-docs/BUILDING/index.html | 5235 ++++ docs/sdk-docs/CHANGELOG/index.html | 7371 ++++++ docs/sdk-docs/CODE_OF_CONDUCT/index.html | 4075 +++ docs/sdk-docs/CONTRIBUTING/index.html | 4146 +++ docs/sdk-docs/GETSTARTED/index.html | 4179 ++++ docs/sdk-docs/LINUX_INTEGRATION/index.html | 4269 ++++ docs/sdk-docs/MIGRATION/index.html | 5733 +++++ .../index.html | 4471 ++++ docs/sdk-docs/NEED_HELP/index.html | 4207 ++++ docs/sdk-docs/SDK_MODULES/index.html | 4510 ++++ docs/sdk-docs/SECURITY/index.html | 4074 +++ docs/sdk-docs/SEQUENCE_DIAGRAMS/index.html | 4080 +++ .../app-components/alexa-auto-apis/index.html | 4086 +++ .../alexa-auto-apl-renderer/index.html | 4229 ++++ .../modules/apl-render/index.html | 4450 ++++ .../alexa-auto-apps-common-ui/index.html | 4025 +++ .../alexa-auto-apps-common-util/index.html | 4032 +++ .../assets/set-fan-speed-to-3.png | Bin 0 -> 39442 bytes .../assets/set-fan-speed-to-3.puml | 27 + .../assets/set-reply-to-engine.png | Bin 0 -> 27595 bytes .../assets/set-reply-to-engine.puml | 23 + .../alexa-auto-carcontrol/index.html | 4292 ++++ .../alexa-auto-comms-ui/index.html | 4067 +++ .../assets/contactsLib-add.png | Bin 0 -> 77449 bytes .../assets/contactsLib-add.puml | 35 + .../assets/contactsLib-remove.png | Bin 0 -> 77267 bytes .../assets/contactsLib-remove.puml | 35 + .../alexa-auto-contacts/index.html | 4248 ++++ .../alexa-auto-device-usage/index.html | 4088 +++ .../alexa-auto-lwa-auth/index.html | 4027 +++ .../alexa-auto-media-player/index.html | 4148 +++ .../alexa-auto-navigation/index.html | 4040 +++ .../alexa-auto-settings/index.html | 4052 +++ .../alexa-auto-setup/index.html | 4098 +++ .../assets/AACSTelephony_initiateCall.png | Bin 0 -> 30260 bytes .../assets/AACSTelephony_initiateCall.puml | 21 + .../alexa-auto-telephony/index.html | 4352 ++++ .../index.html | 4054 +++ .../alexa-auto-tts/assets/Android_TTS.png | Bin 0 -> 99471 bytes .../alexa-auto-tts/assets/Android_TTS.xml | 1 + .../app-components/alexa-auto-tts/index.html | 4281 ++++ .../alexa-auto-ux-restrictions/index.html | 4030 +++ .../alexa-auto-voice-interaction/index.html | 4031 +++ .../alexa-auto-voice-ui/index.html | 4048 +++ .../aacs/android/assets/AACSArchDetailed.png | Bin 0 -> 128039 bytes .../aacs/android/assets/AACSInit.puml | 48 + .../aacs/android/assets/AACSInitFlow.png | Bin 0 -> 86745 bytes .../aacs/android/assets/AACSWakeword.png | Bin 0 -> 226421 bytes .../aacs/android/assets/AACSWakeword.puml | 28 + .../aacs/android/assets/AACS_CBLLogin.png | Bin 0 -> 86098 bytes .../aacs/android/assets/AACS_CBLLogin.puml | 55 + docs/sdk-docs/aacs/android/assets/APCP.png | Bin 0 -> 297074 bytes docs/sdk-docs/aacs/android/assets/config.json | 105 + .../android/common/commonutils/index.html | 4056 +++ .../aacs/android/common/ipc/index.html | 4247 ++++ docs/sdk-docs/aacs/android/index.html | 5061 ++++ .../assets/AACSSampleAppArch.png | Bin 0 -> 152170 bytes .../AACSSampleAppComponentDiagram.drawio | 1 + .../assets/AACSSampleAppComponentDiagram.png | Bin 0 -> 150420 bytes .../aacs/android/sample-app/index.html | 4763 ++++ .../amazon/alexaautoclientservice/index.html | 4113 +++ docs/sdk-docs/aacs/android/service/index.html | 4606 ++++ .../assets/Migration-ApplicationArch.png | Bin 0 -> 52957 bytes docs/sdk-docs/assets/Migration-Hybrid.png | Bin 0 -> 43317 bytes docs/sdk-docs/assets/Migration-Steps.png | Bin 0 -> 132433 bytes docs/sdk-docs/assets/aac-seq-ttt.plantuml | 73 + docs/sdk-docs/assets/aac-seq-ttt.png | Bin 0 -> 60400 bytes docs/sdk-docs/assets/aac-seq-wwe.plantuml | 98 + docs/sdk-docs/assets/aac-seq-wwe.png | Bin 0 -> 78705 bytes .../sdk-docs/assets/aac_linux_integration.png | Bin 0 -> 22351 bytes docs/sdk-docs/assets/images/favicon.png | Bin 0 -> 1870 bytes .../assets/javascripts/bundle.a5f8ea78.min.js | 29 + .../javascripts/bundle.a5f8ea78.min.js.map | 8 + .../javascripts/lunr/min/lunr.ar.min.js | 1 + .../javascripts/lunr/min/lunr.da.min.js | 18 + .../javascripts/lunr/min/lunr.de.min.js | 18 + .../javascripts/lunr/min/lunr.du.min.js | 18 + .../javascripts/lunr/min/lunr.es.min.js | 18 + .../javascripts/lunr/min/lunr.fi.min.js | 18 + .../javascripts/lunr/min/lunr.fr.min.js | 18 + .../javascripts/lunr/min/lunr.hi.min.js | 1 + .../javascripts/lunr/min/lunr.hu.min.js | 18 + .../javascripts/lunr/min/lunr.it.min.js | 18 + .../javascripts/lunr/min/lunr.ja.min.js | 1 + .../javascripts/lunr/min/lunr.jp.min.js | 1 + .../javascripts/lunr/min/lunr.multi.min.js | 1 + .../javascripts/lunr/min/lunr.nl.min.js | 18 + .../javascripts/lunr/min/lunr.no.min.js | 18 + .../javascripts/lunr/min/lunr.pt.min.js | 18 + .../javascripts/lunr/min/lunr.ro.min.js | 18 + .../javascripts/lunr/min/lunr.ru.min.js | 18 + .../lunr/min/lunr.stemmer.support.min.js | 1 + .../javascripts/lunr/min/lunr.sv.min.js | 18 + .../javascripts/lunr/min/lunr.th.min.js | 1 + .../javascripts/lunr/min/lunr.tr.min.js | 18 + .../javascripts/lunr/min/lunr.vi.min.js | 1 + .../javascripts/lunr/min/lunr.zh.min.js | 1 + .../assets/javascripts/lunr/tinyseg.js | 206 + .../assets/javascripts/lunr/wordcut.js | 6708 +++++ .../workers/search.cefbb252.min.js | 48 + .../workers/search.cefbb252.min.js.map | 8 + docs/sdk-docs/assets/number-1.png | Bin 0 -> 827 bytes docs/sdk-docs/assets/number-2.png | Bin 0 -> 923 bytes docs/sdk-docs/assets/number-3.png | Bin 0 -> 908 bytes docs/sdk-docs/assets/number-4.png | Bin 0 -> 906 bytes docs/sdk-docs/assets/number-5.png | Bin 0 -> 908 bytes docs/sdk-docs/assets/number-6.png | Bin 0 -> 905 bytes .../assets/stylesheets/main.a617204b.min.css | 2 + .../stylesheets/main.a617204b.min.css.map | 1 + .../stylesheets/palette.9204c3b2.min.css | 2 + .../stylesheets/palette.9204c3b2.min.css.map | 1 + docs/sdk-docs/builder/index.html | 4321 ++++ docs/sdk-docs/index.html | 4287 ++++ docs/sdk-docs/logo.png | Bin 0 -> 2355 bytes .../modules/aasb/aasb-docs/AASB/index.html | 4203 ++++ .../aasb-docs/AddressBook/index.html | 5212 ++++ .../assets/remove_contacts.plantuml | 36 + .../address-book/assets/remove_contacts.png | Bin 0 -> 20029 bytes .../assets/remove_navigation_fav.plantuml | 37 + .../assets/remove_navigation_fav.png | Bin 0 -> 20520 bytes .../assets/upload_contacts.plantuml | 47 + .../address-book/assets/upload_contacts.png | Bin 0 -> 24273 bytes .../assets/upload_navigation_fav.plantuml | 47 + .../assets/upload_navigation_fav.png | Bin 0 -> 26223 bytes docs/sdk-docs/modules/address-book/index.html | 4385 ++++ .../modules/alexa/aasb-docs/Alerts/index.html | 4662 ++++ .../alexa/aasb-docs/AlexaClient/index.html | 4760 ++++ .../alexa/aasb-docs/AlexaSpeaker/index.html | 4632 ++++ .../alexa/aasb-docs/AudioPlayer/index.html | 4620 ++++ .../alexa/aasb-docs/AuthProvider/index.html | 4729 ++++ .../alexa/aasb-docs/DeviceSetup/index.html | 4358 ++++ .../alexa/aasb-docs/DoNotDisturb/index.html | 4308 ++++ .../aasb-docs/EqualizerController/index.html | 4863 ++++ .../aasb-docs/ExternalMediaAdapter/index.html | 7498 ++++++ .../alexa/aasb-docs/GlobalPreset/index.html | 4187 ++++ .../aasb-docs/LocalMediaSource/index.html | 6053 +++++ .../MediaPlaybackRequestor/index.html | 4473 ++++ .../alexa/aasb-docs/Notifications/index.html | 4335 ++++ .../aasb-docs/PlaybackController/index.html | 4466 ++++ .../aasb-docs/SpeechRecognizer/index.html | 4536 ++++ .../aasb-docs/TemplateRuntime/index.html | 4600 ++++ .../alexa/assets/AuthProvider_login.png | Bin .../alexa/assets/AuthProvider_logout.png | Bin .../assets/DEFAULT_to_DEFAULT_Switching.png | Bin 0 -> 99626 bytes .../alexa/assets/Starting_FM_By_Voice.png | Bin 0 -> 113851 bytes .../assets/Switching_Default_With_GUI.png | Bin 0 -> 140515 bytes .../authprovider-cancel-sequence.plantuml | 0 .../assets/authprovider-cancel-sequence.png | Bin .../authprovider-logout-sequence.plantuml | 0 .../assets/authprovider-logout-sequence.png | Bin .../authprovider-start-sequence.plantuml | 0 .../assets/authprovider-start-sequence.png | Bin ...plete-interaction-tap-to-talk-sequence.svg | 166 + ...-interaction-tap-to-talk-sequence.plantuml | 160 + docs/sdk-docs/modules/alexa/index.html | 5805 +++++ .../modules/apl/aasb-docs/APL/index.html | 6026 +++++ .../apl/assets/aac-apl-general-flow.png | Bin 0 -> 49047 bytes .../aac-apl-platform-properties.plantuml | 41 + .../assets/aac-apl-render-document.plantuml | 47 + .../aac-apl-set-platform-properties.png | Bin 0 -> 35862 bytes docs/sdk-docs/modules/apl/index.html | 4420 ++++ .../modules}/bluetooth/assets/ble.plantuml | 0 .../modules}/bluetooth/assets/ble.png | Bin .../assets/bluetooth_classic.plantuml | 0 .../bluetooth/assets/bluetooth_classic.png | Bin docs/sdk-docs/modules/bluetooth/index.html | 4498 ++++ .../aasb-docs/CarControl/index.html | 5286 ++++ .../car-control/assets/CarControlConfig.json | 11710 +++++++++ .../adjusting_mode_of_a_setting.plantuml | 45 + .../assets/adjusting_mode_of_a_setting.png | Bin 0 -> 29596 bytes .../adjusting_value_of_a_setting.plantuml | 45 + .../assets/adjusting_value_of_a_setting.png | Bin 0 -> 30030 bytes .../modules/car-control/assets/assets-1P.json | 20600 +++++++++++++++ .../assets/carcontrol_sequence_online.png | Bin .../assets/setting_mode_of_a_setting.plantuml | 45 + .../assets/setting_mode_of_a_setting.png | Bin 0 -> 28043 bytes .../setting_value_of_a_setting.plantuml | 45 + .../assets/setting_value_of_a_setting.png | Bin 0 -> 29274 bytes .../assets/turning_off_endpoint.plantuml | 45 + .../assets/turning_off_endpoint.png | Bin 0 -> 27397 bytes ...rning_off_toggle_state_of_setting.plantuml | 45 + .../turning_off_toggle_state_of_setting.png | Bin 0 -> 28347 bytes .../assets/turning_on_endpoint.plantuml | 45 + .../assets/turning_on_endpoint.png | Bin 0 -> 27276 bytes ...urning_on_toggle_state_of_setting.plantuml | 45 + .../turning_on_toggle_state_of_setting.png | Bin 0 -> 28246 bytes docs/sdk-docs/modules/car-control/index.html | 8272 ++++++ .../modules/cbl/aasb-docs/CBL/index.html | 4992 ++++ .../cbl/assets/cbl-cancel-sequence.plantuml | 0 .../cbl/assets/cbl-cancel-sequence.png | Bin .../cbl/assets/cbl-logout-sequence.plantuml | 0 .../cbl/assets/cbl-logout-sequence.png | Bin .../cbl/assets/cbl-refresh-sequence.plantuml | 0 .../cbl/assets/cbl-refresh-sequence.png | Bin .../cbl/assets/cbl-start-sequence.plantuml | 0 .../modules/cbl/assets/cbl-start-sequence.png | Bin .../sdk-docs}/modules/cbl/assets/cbl_auth.png | Bin .../cbl/assets/cbl_dereg_inactivity.png | Bin .../cbl/assets/cbl_dereg_user_interaction.png | Bin .../modules/cbl/assets/cbl_refresh.png | Bin docs/sdk-docs/modules/cbl/index.html | 4257 ++++ .../aasb-docs/AlexaConnectivity/index.html | 4850 ++++ .../Connectivity-Sequence-CloudAskReport.png | Bin 0 -> 21281 bytes .../Connectivity-Sequence-CloudAskReport.puml | 37 + .../Connectivity-Sequence-DeviceDiscovery.png | Bin 0 -> 13800 bytes ...Connectivity-Sequence-DeviceDiscovery.puml | 29 + ...ctivity-Sequence-sendConnectivityEvent.png | Bin 0 -> 42912 bytes ...tivity-Sequence-sendConnectivityEvent.puml | 50 + docs/sdk-docs/modules/connectivity/index.html | 4372 ++++ docs/sdk-docs/modules/core/AUDIO/index.html | 4423 ++++ .../modules/core/AUTHORIZATION/index.html | 4284 ++++ .../core/RUNTIME_PROPERTIES/index.html | 4177 ++++ .../core/aasb-docs/AudioInput/index.html | 4389 ++++ .../core/aasb-docs/AudioOutput/index.html | 6983 ++++++ .../core/aasb-docs/Authorization/index.html | 5225 ++++ .../core/aasb-docs/DeviceUsage/index.html | 4187 ++++ .../aasb-docs/LocationProvider/index.html | 4737 ++++ .../aasb-docs/NetworkInfoProvider/index.html | 4624 ++++ .../core/aasb-docs/PropertyManager/index.html | 4719 ++++ docs/sdk-docs/modules/core/index.html | 5032 ++++ .../aasb-docs/CustomDomain/index.html | 4893 ++++ .../custom-domain/assets/custom_context.png | Bin 0 -> 66603 bytes .../assets/custom_directives_events.png | Bin 0 -> 111921 bytes .../sdk-docs/modules/custom-domain/index.html | 4239 ++++ .../assets}/loopback-detector-data-flow.png | Bin .../modules/loopback-detector/index.html | 4212 ++++ .../messaging/aasb-docs/Messaging/index.html | 5268 ++++ .../aac-messaging-reading-messages.plantuml | 47 + .../assets/aac-messaging-reading-messages.png | Bin 0 -> 43716 bytes .../aac-messaging-reply-message.plantuml | 65 + .../assets/aac-messaging-reply-message.png | Bin 0 -> 64698 bytes .../aac-messaging-sending-messages.plantuml | 41 + .../assets/aac-messaging-sending-messages.png | Bin 0 -> 31238 bytes ...ssaging-endpoint-state-connection.plantuml | 35 + ...te-messaging-endpoint-state-connection.png | Bin 0 -> 19474 bytes ...saging-endpoint-state-permissions.plantuml | 35 + ...e-messaging-endpoint-state-permissions.png | Bin 0 -> 25981 bytes docs/sdk-docs/modules/messaging/index.html | 4347 ++++ .../aasb-docs/Navigation/index.html | 5888 +++++ .../navigation/assets/add_waypoint.plantuml | 77 + .../navigation/assets/add_waypoint.png | Bin 0 -> 91249 bytes .../assets/announce_maneuver.plantuml | 49 + .../navigation/assets/announce_maneuver.png | Bin 0 -> 54803 bytes .../assets/announce_road_regulation.plantuml | 49 + .../assets/announce_road_regulation.png | Bin 0 -> 56540 bytes .../assets/cancel_navigation.plantuml | 43 + .../navigation/assets/cancel_navigation.png | Bin 0 -> 37031 bytes .../navigation/assets/map_control.plantuml | 49 + .../modules/navigation/assets/map_control.png | Bin 0 -> 44901 bytes .../navigate_previous_waypoint.plantuml | 49 + .../assets/navigate_previous_waypoint.png | Bin 0 -> 55935 bytes .../assets/remove_waypoint.plantuml | 76 + .../navigation/assets/remove_waypoint.png | Bin 0 -> 99214 bytes .../assets/show_alternate_routes.plantuml | 49 + .../assets/show_alternate_routes.png | Bin 0 -> 64231 bytes .../assets/show_previous_waypoints.plantuml | 49 + .../assets/show_previous_waypoints.png | Bin 0 -> 55237 bytes .../assets/start_navigation.plantuml | 54 + .../navigation/assets/start_navigation.png | Bin 0 -> 55261 bytes docs/sdk-docs/modules/navigation/index.html | 5071 ++++ .../aasb-docs/PhoneCallController/index.html | 5811 +++++ .../aac-pcc-connection-state-changed.plantuml | 33 + .../aac-pcc-connection-state-changed.png | Bin 0 -> 20353 bytes ...-pcc-device-configuration-updated.plantuml | 27 + .../aac-pcc-device-configuration-updated.png | Bin 0 -> 15299 bytes .../assets/aac-pcc-inbound-call.plantuml | 74 + .../assets/aac-pcc-inbound-call.png | Bin 0 -> 83522 bytes .../assets/aac-pcc-outbound-call.plantuml | 54 + .../assets/aac-pcc-outbound-call.png | Bin 0 -> 51866 bytes .../sdk-docs/modules/phone-control/index.html | 4398 ++++ docs/sdk-docs/modules/system-audio/index.html | 4338 ++++ .../text-to-speech-provider/index.html | 4190 ++++ .../aasb-docs/TextToSpeech/index.html | 4671 ++++ .../assets/GetCapabilities.plantuml | 33 + .../text-to-speech/assets/GetCapabilities.png | Bin 0 -> 14640 bytes .../assets/PrepareSpeech.plantuml | 35 + .../text-to-speech/assets/PrepareSpeech.png | Bin 0 -> 18932 bytes .../modules/text-to-speech/index.html | 4260 ++++ docs/sdk-docs/samples/cpp/index.html | 4452 ++++ docs/sdk-docs/search/search_index.json | 1 + docs/sdk-docs/sitemap.xml | 473 + docs/sdk-docs/sitemap.xml.gz | Bin 0 -> 250 bytes extensions/README.md | 1 + extensions/aasb/.gitignore | 3 - extensions/aasb/CMakeLists.txt | 20 - extensions/aasb/README.md | 339 - extensions/aasb/assets/AASBNewArch.png | Bin 55519 -> 0 bytes extensions/aasb/assets/AASBOldArch.png | Bin 36815 -> 0 bytes .../aasb/docs/AASB/StartServiceMessage.html | 436 - .../aasb/docs/AASB/StopServiceMessage.html | 436 - .../APL/ClearAllExecuteCommandsMessage.html | 488 - .../aasb/docs/APL/ClearCardMessage.html | 488 - .../aasb/docs/APL/ClearDocumentMessage.html | 497 - .../docs/APL/DataSourceUpdateMessage.html | 519 - .../aasb/docs/APL/ExecuteCommandsMessage.html | 508 - .../APL/ExecuteCommandsResultMessage.html | 519 - .../APL/InterruptCommandSequenceMessage.html | 497 - .../docs/APL/ProcessActivityEventMessage.html | 515 - .../aasb/docs/APL/RenderDocumentMessage.html | 519 - .../docs/APL/RenderDocumentResultMessage.html | 519 - ...endDataSourceFetchRequestEventMessage.html | 508 - .../APL/SendDeviceWindowStateMessage.html | 497 - .../docs/APL/SendDocumentStateMessage.html | 497 - .../APL/SendRuntimeErrorEventMessage.html | 497 - .../aasb/docs/APL/SendUserEventMessage.html | 497 - .../docs/APL/SetAPLMaxVersionMessage.html | 497 - .../APL/SetDocumentIdleTimeoutMessage.html | 497 - .../AddressBook/AddAddressBookMessage.html | 862 - .../AddAddressBookMessageReply.html | 484 - .../AddressBook/RemoveAddressBookMessage.html | 471 - .../RemoveAddressBookMessageReply.html | 484 - .../aasb/docs/Alerts/AlertCreatedMessage.html | 484 - .../aasb/docs/Alerts/AlertDeletedMessage.html | 473 - .../docs/Alerts/AlertStateChangedMessage.html | 508 - .../aasb/docs/Alerts/LocalStopMessage.html | 464 - .../docs/Alerts/RemoveAllAlertsMessage.html | 466 - .../AlexaClient/AuthStateChangedMessage.html | 504 - .../ConnectionStatusChangedMessage.html | 506 - .../DialogStateChangedMessage.html | 478 - .../StopForegroundActivityMessage.html | 462 - .../ConnectivityStateChangeMessage.html | 471 - .../ConnectivityStateChangeMessageReply.html | 492 - .../GetConnectivityStateMessage.html | 470 - .../GetConnectivityStateMessageReply.html | 492 - .../GetIdentifierMessage.html | 470 - .../GetIdentifierMessageReply.html | 492 - .../SendConnectivityEventMessage.html | 479 - .../SendConnectivityEventMessageReply.html | 496 - .../LocalAdjustVolumeMessage.html | 490 - .../AlexaSpeaker/LocalSetMuteMessage.html | 489 - .../AlexaSpeaker/LocalSetVolumeMessage.html | 489 - .../SpeakerSettingsChangedMessage.html | 509 - .../AudioInput/StartAudioInputMessage.html | 491 - .../AudioInput/StopAudioInputMessage.html | 464 - .../docs/AudioOutput/GetDurationMessage.html | 508 - .../AudioOutput/GetDurationMessageReply.html | 510 - .../GetNumBytesBufferedMessage.html | 508 - .../GetNumBytesBufferedMessageReply.html | 510 - .../docs/AudioOutput/GetPositionMessage.html | 508 - .../AudioOutput/GetPositionMessageReply.html | 510 - .../docs/AudioOutput/MediaErrorMessage.html | 526 - .../AudioOutput/MediaStateChangedMessage.html | 524 - .../AudioOutput/MutedStateChangedMessage.html | 512 - .../aasb/docs/AudioOutput/PauseMessage.html | 508 - .../aasb/docs/AudioOutput/PlayMessage.html | 508 - .../AudioOutput/PrepareStreamMessage.html | 602 - .../docs/AudioOutput/PrepareURLMessage.html | 557 - .../aasb/docs/AudioOutput/ResumeMessage.html | 508 - .../docs/AudioOutput/SetPositionMessage.html | 519 - .../aasb/docs/AudioOutput/StopMessage.html | 508 - .../AudioOutput/VolumeChangedMessage.html | 508 - .../AudioPlayer/GetPlayerDurationMessage.html | 464 - .../GetPlayerDurationMessageReply.html | 486 - .../AudioPlayer/GetPlayerPositionMessage.html | 464 - .../GetPlayerPositionMessageReply.html | 486 - .../PlayerActivityChangedMessage.html | 481 - .../AuthProvider/AuthStateChangedMessage.html | 510 - .../AuthProvider/GetAuthStateMessage.html | 468 - .../GetAuthStateMessageReply.html | 492 - .../AuthProvider/GetAuthTokenMessage.html | 469 - .../GetAuthTokenMessageReply.html | 486 - .../AuthorizationErrorMessage.html | 505 - .../AuthorizationStateChangedMessage.html | 499 - .../CancelAuthorizationMessage.html | 483 - .../Authorization/EventReceivedMessage.html | 494 - .../GetAuthorizationDataMessage.html | 494 - .../GetAuthorizationDataMessageReply.html | 496 - .../docs/Authorization/LogoutMessage.html | 483 - .../docs/Authorization/SendEventMessage.html | 494 - .../SetAuthorizationDataMessage.html | 505 - .../StartAuthorizationMessage.html | 494 - .../aasb/docs/CBL/CBLStateChangedMessage.html | 534 - extensions/aasb/docs/CBL/CancelMessage.html | 476 - .../docs/CBL/ClearRefreshTokenMessage.html | 476 - .../aasb/docs/CBL/GetRefreshTokenMessage.html | 476 - .../docs/CBL/GetRefreshTokenMessageReply.html | 494 - extensions/aasb/docs/CBL/ResetMessage.html | 476 - .../aasb/docs/CBL/SetRefreshTokenMessage.html | 485 - .../aasb/docs/CBL/SetUserProfileMessage.html | 496 - extensions/aasb/docs/CBL/StartMessage.html | 476 - .../AdjustControllerValueMessageReply.html | 493 - .../AdjustModeControllerValueMessage.html | 508 - .../AdjustRangeControllerValueMessage.html | 508 - .../SetControllerValueMessageReply.html | 495 - .../SetModeControllerValueMessage.html | 508 - .../SetPowerControllerValueMessage.html | 497 - .../SetRangeControllerValueMessage.html | 508 - .../SetToggleControllerValueMessage.html | 508 - .../DeviceSetup/SetupCompletedMessage.html | 458 - .../SetupCompletedResponseMessage.html | 471 - .../ReportNetworkDataUsageMessage.html | 462 - .../DoNotDisturbChangedMessage.html | 467 - .../DoNotDisturb/SetDoNotDisturbMessage.html | 467 - .../GetBandLevelsMessage.html | 467 - .../GetBandLevelsMessageReply.html | 523 - .../LocalAdjustBandLevelsMessage.html | 512 - .../LocalResetBandsMessage.html | 475 - .../LocalSetBandLevelsMessage.html | 511 - .../SetBandLevelsMessage.html | 510 - .../AdjustSeekMessage.html | 510 - .../AuthorizeMessage.html | 530 - .../ExternalMediaAdapter/GetStateMessage.html | 935 - .../LoginCompleteMessage.html | 499 - .../ExternalMediaAdapter/LoginMessage.html | 543 - .../LogoutCompleteMessage.html | 499 - .../ExternalMediaAdapter/LogoutMessage.html | 499 - .../MutedStateChangedMessage.html | 505 - .../PlayControlMessage.html | 527 - .../ExternalMediaAdapter/PlayMessage.html | 559 - .../PlayerErrorMessage.html | 543 - .../PlayerEventMessage.html | 510 - .../RemoveDiscoveredPlayerMessage.html | 499 - .../ReportDiscoveredPlayersMessage.html | 578 - .../RequestTokenMessage.html | 499 - .../ExternalMediaAdapter/SeekMessage.html | 510 - .../ExternalMediaAdapter/SetFocusMessage.html | 499 - .../VolumeChangedMessage.html | 500 - .../GlobalPreset/SetGlobalPresetMessage.html | 462 - .../LocalMediaSource/AdjustSeekMessage.html | 508 - .../LocalMediaSource/GetStateMessage.html | 497 - .../GetStateMessageReply.html | 923 - .../MutedStateChangedMessage.html | 509 - .../LocalMediaSource/PlayControlMessage.html | 525 - .../docs/LocalMediaSource/PlayMessage.html | 535 - .../LocalMediaSource/PlayerErrorMessage.html | 552 - .../LocalMediaSource/PlayerEventMessage.html | 519 - .../docs/LocalMediaSource/SeekMessage.html | 508 - .../LocalMediaSource/SetFocusMessage.html | 501 - .../VolumeChangedMessage.html | 509 - .../LocationProvider/GetCountryMessage.html | 464 - .../GetCountryMessageReply.html | 486 - .../LocationProvider/GetLocationMessage.html | 464 - .../GetLocationMessageReply.html | 533 - .../LocationServiceAccessChangedMessage.html | 477 - extensions/aasb/docs/MainMenu.html | 307 - .../Messaging/ConversationsReportMessage.html | 492 - .../Messaging/SendMessageFailedMessage.html | 508 - .../docs/Messaging/SendMessageMessage.html | 503 - .../SendMessageSucceededMessage.html | 481 - .../UpdateMessagesStatusFailedMessage.html | 508 - .../UpdateMessagesStatusMessage.html | 503 - .../UpdateMessagesStatusSucceededMessage.html | 481 - .../UpdateMessagingEndpointStateMessage.html | 515 - .../Messaging/UploadConversationsMessage.html | 481 - .../Navigation/AnnounceManeuverMessage.html | 489 - .../AnnounceRoadRegulationMessage.html | 493 - .../Navigation/CancelNavigationMessage.html | 480 - .../Navigation/ControlDisplayMessage.html | 507 - .../Navigation/GetNavigationStateMessage.html | 480 - .../GetNavigationStateMessageReply.html | 502 - .../NavigateToPreviousWaypointMessage.html | 480 - .../Navigation/NavigationErrorMessage.html | 549 - .../Navigation/NavigationEventMessage.html | 520 - .../ShowAlternativeRoutesMessage.html | 494 - ...ShowAlternativeRoutesSucceededMessage.html | 489 - .../ShowPreviousWaypointsMessage.html | 480 - .../Navigation/StartNavigationMessage.html | 489 - .../GetNetworkStatusMessage.html | 464 - .../GetNetworkStatusMessageReply.html | 493 - .../GetWifiSignalStrengthMessage.html | 464 - .../GetWifiSignalStrengthMessageReply.html | 486 - .../NetworkStatusChangedMessage.html | 491 - .../OnNotificationReceivedMessage.html | 455 - .../Notifications/SetIndicatorMessage.html | 469 - .../PhoneCallController/AnswerMessage.html | 491 - .../CallFailedMessage.html | 520 - .../CallStateChangedMessage.html | 521 - .../CallerIdReceivedMessage.html | 502 - .../ConnectionStateChangedMessage.html | 495 - .../CreateCallIdMessage.html | 482 - .../CreateCallIdMessageReply.html | 504 - .../DeviceConfigurationUpdatedMessage.html | 491 - .../docs/PhoneCallController/DialMessage.html | 491 - .../PhoneCallController/RedialMessage.html | 491 - .../SendDTMFFailedMessage.html | 517 - .../PhoneCallController/SendDTMFMessage.html | 491 - .../SendDTMFSucceededMessage.html | 491 - .../docs/PhoneCallController/StopMessage.html | 491 - .../ButtonPressedMessage.html | 474 - .../TogglePressedMessage.html | 484 - .../PropertyManager/GetPropertyMessage.html | 473 - .../GetPropertyMessageReply.html | 497 - .../PropertyChangedMessage.html | 484 - .../PropertyStateChangedMessage.html | 499 - .../PropertyManager/SetPropertyMessage.html | 484 - .../docs/Publish Message General Form.html | 489 - .../aasb/docs/Reply Message General Form.html | 502 - .../EndOfSpeechDetectedMessage.html | 463 - .../SpeechRecognizer/StartCaptureMessage.html | 513 - .../SpeechRecognizer/StopCaptureMessage.html | 463 - .../WakewordDetectedMessage.html | 471 - .../ClearPlayerInfoMessage.html | 464 - .../TemplateRuntime/ClearTemplateMessage.html | 464 - .../DisplayCardClearedMessage.html | 464 - .../RenderPlayerInfoMessage.html | 519 - .../RenderTemplateMessage.html | 489 - .../TextToSpeech/GetCapabilitiesMessage.html | 473 - .../GetCapabilitiesMessageReply.html | 486 - .../PrepareSpeechCompletedMessage.html | 558 - .../PrepareSpeechFailedMessage.html | 484 - .../TextToSpeech/PrepareSpeechMessage.html | 506 - extensions/aasb/meta-aac-aasb/conf/layer.conf | 1 - .../modules/aasb-address-book/CMakeLists.txt | 57 - .../aac-aasb-address-book.bb | 7 - .../aasb-address-book/engine/CMakeLists.txt | 60 - .../AddressBook/AddAddressBookMessage.h | 154 - .../AddressBook/AddAddressBookMessageReply.h | 144 - .../AddressBook/AddressBook/AddressBook.h | 79 - .../AddressBook/AddressBook/AddressBookType.h | 81 - .../AddressBook/AddressBook/ContactName.h | 85 - .../AddressBook/AddressBook/NavigationName.h | 74 - .../AddressBook/AddressBook/PhoneData.h | 72 - .../AddressBook/AddressBook/PostalAddress.h | 102 - .../AddressBook/RemoveAddressBookMessage.h | 141 - .../RemoveAddressBookMessageReply.h | 144 - .../aasb/modules/aasb-alexa/CMakeLists.txt | 47 - .../aasb/modules/aasb-alexa/aac-aasb-alexa.bb | 7 - .../modules/aasb-alexa/engine/CMakeLists.txt | 197 - .../Alexa/Alerts/AlertCreatedMessage.h | 144 - .../Alexa/Alerts/AlertDeletedMessage.h | 141 - .../AASB/Message/Alexa/Alerts/AlertState.h | 117 - .../Alexa/Alerts/AlertStateChangedMessage.h | 150 - .../Message/Alexa/Alerts/LocalStopMessage.h | 136 - .../Alexa/Alerts/RemoveAllAlertsMessage.h | 136 - .../Message/Alexa/AlexaClient/AuthError.h | 129 - .../Message/Alexa/AlexaClient/AuthState.h | 89 - .../AlexaClient/AuthStateChangedMessage.h | 149 - .../AlexaClient/ConnectionChangedReason.h | 141 - .../Alexa/AlexaClient/ConnectionStatus.h | 85 - .../ConnectionStatusChangedMessage.h | 149 - .../Message/Alexa/AlexaClient/DialogState.h | 93 - .../AlexaClient/DialogStateChangedMessage.h | 144 - .../StopForegroundActivityMessage.h | 136 - .../AlexaSpeaker/LocalAdjustVolumeMessage.h | 147 - .../Alexa/AlexaSpeaker/LocalSetMuteMessage.h | 147 - .../AlexaSpeaker/LocalSetVolumeMessage.h | 147 - .../SpeakerSettingsChangedMessage.h | 153 - .../Message/Alexa/AlexaSpeaker/SpeakerType.h | 81 - .../AudioPlayer/GetPlayerDurationMessage.h | 136 - .../GetPlayerDurationMessageReply.h | 144 - .../AudioPlayer/GetPlayerPositionMessage.h | 136 - .../GetPlayerPositionMessageReply.h | 144 - .../Alexa/AudioPlayer/PlayerActivity.h | 97 - .../PlayerActivityChangedMessage.h | 144 - .../AuthProvider/AuthStateChangedMessage.h | 149 - .../Alexa/AuthProvider/GetAuthStateMessage.h | 136 - .../AuthProvider/GetAuthStateMessageReply.h | 147 - .../Alexa/AuthProvider/GetAuthTokenMessage.h | 136 - .../AuthProvider/GetAuthTokenMessageReply.h | 144 - .../Alexa/DeviceSetup/SetupCompletedMessage.h | 136 - .../SetupCompletedResponseMessage.h | 144 - .../Message/Alexa/DeviceSetup/StatusCode.h | 83 - .../DoNotDisturb/DoNotDisturbChangedMessage.h | 141 - .../DoNotDisturb/SetDoNotDisturbMessage.h | 141 - .../Alexa/EqualizerController/EqualizerBand.h | 85 - .../EqualizerController/EqualizerBandLevel.h | 70 - .../GetBandLevelsMessage.h | 136 - .../GetBandLevelsMessageReply.h | 147 - .../LocalAdjustBandLevelsMessage.h | 144 - .../LocalResetBandsMessage.h | 146 - .../LocalSetBandLevelsMessage.h | 144 - .../SetBandLevelsMessage.h | 144 - .../ExternalMediaAdapter/AdjustSeekMessage.h | 144 - .../ExternalMediaAdapter/AuthorizeMessage.h | 144 - .../AuthorizedPlayerInfo.h | 67 - .../DiscoveredPlayerInfo.h | 77 - .../ExternalMediaAdapterState.h | 69 - .../Alexa/ExternalMediaAdapter/Favorites.h | 85 - .../ExternalMediaAdapter/GetStateMessage.h | 147 - .../LoginCompleteMessage.h | 141 - .../Alexa/ExternalMediaAdapter/LoginMessage.h | 153 - .../LogoutCompleteMessage.h | 141 - .../ExternalMediaAdapter/LogoutMessage.h | 141 - .../Alexa/ExternalMediaAdapter/MediaType.h | 97 - .../Alexa/ExternalMediaAdapter/MutedState.h | 81 - .../MutedStateChangedMessage.h | 144 - .../Alexa/ExternalMediaAdapter/Navigation.h | 85 - .../ExternalMediaAdapter/PlayControlMessage.h | 147 - .../ExternalMediaAdapter/PlayControlType.h | 133 - .../Alexa/ExternalMediaAdapter/PlayMessage.h | 159 - .../PlaybackStateExternal.h | 140 - .../ExternalMediaAdapter/PlayerErrorMessage.h | 153 - .../ExternalMediaAdapter/PlayerEventMessage.h | 144 - .../RemoveDiscoveredPlayerMessage.h | 141 - .../ReportDiscoveredPlayersMessage.h | 144 - .../RequestTokenMessage.h | 141 - .../Alexa/ExternalMediaAdapter/SeekMessage.h | 144 - .../SessionStateExternal.h | 91 - .../ExternalMediaAdapter/SetFocusMessage.h | 141 - .../SupportedPlaybackOperation.h | 141 - .../ExternalMediaAdapter/ValidationMethod.h | 85 - .../VolumeChangedMessage.h | 141 - .../GlobalPreset/SetGlobalPresetMessage.h | 141 - .../LocalMediaSource/AdjustSeekMessage.h | 147 - .../Alexa/LocalMediaSource/ContentSelector.h | 87 - .../Alexa/LocalMediaSource/GetStateMessage.h | 144 - .../LocalMediaSource/GetStateMessageReply.h | 145 - .../LocalMediaSource/LocalMediaSourceState.h | 71 - .../MutedStateChangedMessage.h | 149 - .../LocalMediaSource/PlayControlMessage.h | 149 - .../Alexa/LocalMediaSource/PlayMessage.h | 155 - .../Alexa/LocalMediaSource/PlaybackState.h | 142 - .../LocalMediaSource/PlayerErrorMessage.h | 161 - .../LocalMediaSource/PlayerEventMessage.h | 152 - .../Alexa/LocalMediaSource/SeekMessage.h | 147 - .../Alexa/LocalMediaSource/SessionState.h | 96 - .../Alexa/LocalMediaSource/SetFocusMessage.h | 144 - .../Message/Alexa/LocalMediaSource/Source.h | 115 - .../LocalMediaSource/VolumeChangedMessage.h | 147 - .../Alexa/Notifications/IndicatorState.h | 85 - .../OnNotificationReceivedMessage.h | 136 - .../Alexa/Notifications/SetIndicatorMessage.h | 144 - .../PlaybackController/ButtonPressedMessage.h | 144 - .../Alexa/PlaybackController/PlaybackButton.h | 97 - .../Alexa/PlaybackController/PlaybackToggle.h | 93 - .../PlaybackController/TogglePressedMessage.h | 147 - .../EndOfSpeechDetectedMessage.h | 136 - .../Alexa/SpeechRecognizer/Initiator.h | 85 - .../SpeechRecognizer/StartCaptureMessage.h | 159 - .../SpeechRecognizer/StopCaptureMessage.h | 136 - .../WakewordDetectedMessage.h | 141 - .../TemplateRuntime/ClearPlayerInfoMessage.h | 136 - .../TemplateRuntime/ClearTemplateMessage.h | 136 - .../DisplayCardClearedMessage.h | 136 - .../Alexa/TemplateRuntime/FocusState.h | 85 - .../TemplateRuntime/RenderPlayerInfoMessage.h | 155 - .../TemplateRuntime/RenderTemplateMessage.h | 147 - .../aasb/modules/aasb-apl/CMakeLists.txt | 46 - .../aasb/modules/aasb-apl/aac-aasb-apl.bb | 7 - .../modules/aasb-apl/engine/CMakeLists.txt | 67 - .../AASB/Message/Apl/APL/ActivityEvent.h | 93 - .../Apl/APL/ClearAllExecuteCommandsMessage.h | 136 - .../AASB/Message/Apl/APL/ClearCardMessage.h | 136 - .../Message/Apl/APL/ClearDocumentMessage.h | 141 - .../Message/Apl/APL/DataSourceUpdateMessage.h | 147 - .../Message/Apl/APL/ExecuteCommandsMessage.h | 144 - .../Apl/APL/ExecuteCommandsResultMessage.h | 147 - .../Apl/APL/InterruptCommandSequenceMessage.h | 141 - .../Apl/APL/ProcessActivityEventMessage.h | 147 - .../Message/Apl/APL/RenderDocumentMessage.h | 147 - .../Apl/APL/RenderDocumentResultMessage.h | 147 - .../SendDataSourceFetchRequestEventMessage.h | 144 - .../Apl/APL/SendDeviceWindowStateMessage.h | 141 - .../Apl/APL/SendDocumentStateMessage.h | 141 - .../Apl/APL/SendRuntimeErrorEventMessage.h | 141 - .../Message/Apl/APL/SendUserEventMessage.h | 141 - .../Message/Apl/APL/SetAPLMaxVersionMessage.h | 141 - .../Apl/APL/SetDocumentIdleTimeoutMessage.h | 141 - .../modules/aasb-car-control/CMakeLists.txt | 46 - .../aasb-car-control/aac-aasb-car-control.bb | 7 - .../aasb-car-control/engine/CMakeLists.txt | 58 - .../AdjustControllerValueMessageReply.h | 144 - .../AdjustModeControllerValueMessage.h | 156 - .../AdjustRangeControllerValueMessage.h | 156 - .../SetControllerValueMessageReply.h | 144 - .../SetModeControllerValueMessage.h | 156 - .../SetPowerControllerValueMessage.h | 153 - .../SetRangeControllerValueMessage.h | 156 - .../SetToggleControllerValueMessage.h | 156 - .../aasb/modules/aasb-cbl/CMakeLists.txt | 47 - .../aasb/modules/aasb-cbl/aac-aasb-cbl.bb | 7 - .../modules/aasb-cbl/engine/CMakeLists.txt | 61 - .../AASB/Engine/CBL/AASBCBLEngineService.h | 44 - .../include/AASB/Message/Cbl/CBL/CBLState.h | 97 - .../Message/Cbl/CBL/CBLStateChangedMessage.h | 155 - .../Message/Cbl/CBL/CBLStateChangedReason.h | 97 - .../AASB/Message/Cbl/CBL/CancelMessage.h | 136 - .../Cbl/CBL/ClearRefreshTokenMessage.h | 136 - .../Message/Cbl/CBL/GetRefreshTokenMessage.h | 136 - .../Cbl/CBL/GetRefreshTokenMessageReply.h | 144 - .../AASB/Message/Cbl/CBL/ResetMessage.h | 136 - .../Message/Cbl/CBL/SetRefreshTokenMessage.h | 141 - .../Message/Cbl/CBL/SetUserProfileMessage.h | 144 - .../AASB/Message/Cbl/CBL/StartMessage.h | 136 - .../modules/aasb-connectivity/CMakeLists.txt | 46 - .../aac-aasb-connectivity.bb | 7 - .../aasb-connectivity/engine/CMakeLists.txt | 54 - .../ConnectivityStateChangeMessage.h | 136 - .../ConnectivityStateChangeMessageReply.h | 144 - .../GetConnectivityStateMessage.h | 136 - .../GetConnectivityStateMessageReply.h | 144 - .../AlexaConnectivity/GetIdentifierMessage.h | 136 - .../GetIdentifierMessageReply.h | 144 - .../SendConnectivityEventMessage.h | 141 - .../SendConnectivityEventMessageReply.h | 147 - .../AlexaConnectivity/StatusCode.h | 83 - .../aasb/modules/aasb-core/CMakeLists.txt | 45 - .../aasb/modules/aasb-core/aac-aasb-core.bb | 7 - .../modules/aasb-core/engine/CMakeLists.txt | 160 - .../AASB/Engine/Audio/AASBAudioInput.h | 94 - .../Engine/Audio/AASBAudioInputProvider.h | 59 - .../AASB/Engine/Audio/AASBAudioOutput.h | 97 - .../Engine/Audio/AASBAudioOutputProvider.h | 56 - .../Audio/AudioInput/AudioInputAudioType.h | 85 - .../Audio/AudioInput/StartAudioInputMessage.h | 150 - .../Audio/AudioInput/StopAudioInputMessage.h | 141 - .../Audio/AudioOutput/AudioOutputAudioType.h | 101 - .../Audio/AudioOutput/AudioOutputSourceType.h | 81 - .../Audio/AudioOutput/AudioStreamEncoding.h | 89 - .../Audio/AudioOutput/AudioStreamProperty.h | 67 - .../Audio/AudioOutput/GetDurationMessage.h | 144 - .../AudioOutput/GetDurationMessageReply.h | 144 - .../AudioOutput/GetNumBytesBufferedMessage.h | 144 - .../GetNumBytesBufferedMessageReply.h | 144 - .../Audio/AudioOutput/GetPositionMessage.h | 144 - .../AudioOutput/GetPositionMessageReply.h | 144 - .../Message/Audio/AudioOutput/MediaError.h | 93 - .../Audio/AudioOutput/MediaErrorMessage.h | 152 - .../Message/Audio/AudioOutput/MediaState.h | 85 - .../AudioOutput/MediaStateChangedMessage.h | 150 - .../Message/Audio/AudioOutput/MutedState.h | 81 - .../AudioOutput/MutedStateChangedMessage.h | 147 - .../Message/Audio/AudioOutput/PauseMessage.h | 144 - .../Message/Audio/AudioOutput/PlayMessage.h | 144 - .../Audio/AudioOutput/PrepareStreamMessage.h | 173 - .../Audio/AudioOutput/PrepareURLMessage.h | 165 - .../Message/Audio/AudioOutput/ResumeMessage.h | 144 - .../Audio/AudioOutput/SetPositionMessage.h | 147 - .../Message/Audio/AudioOutput/StopMessage.h | 144 - .../Audio/AudioOutput/VolumeChangedMessage.h | 144 - .../Authorization/AuthorizationErrorMessage.h | 147 - .../Authorization/AuthorizationState.h | 85 - .../AuthorizationStateChangedMessage.h | 147 - .../CancelAuthorizationMessage.h | 141 - .../Authorization/EventReceivedMessage.h | 144 - .../GetAuthorizationDataMessage.h | 144 - .../GetAuthorizationDataMessageReply.h | 144 - .../Authorization/LogoutMessage.h | 141 - .../Authorization/SendEventMessage.h | 144 - .../SetAuthorizationDataMessage.h | 147 - .../Authorization/StartAuthorizationMessage.h | 144 - .../ReportNetworkDataUsageMessage.h | 141 - .../LocationProvider/GetCountryMessage.h | 136 - .../LocationProvider/GetCountryMessageReply.h | 144 - .../LocationProvider/GetLocationMessage.h | 136 - .../GetLocationMessageReply.h | 147 - .../Location/LocationProvider/Location.h | 77 - .../LocationProvider/LocationServiceAccess.h | 81 - .../LocationServiceAccessChangedMessage.h | 144 - .../GetNetworkStatusMessage.h | 136 - .../GetNetworkStatusMessageReply.h | 147 - .../GetWifiSignalStrengthMessage.h | 136 - .../GetWifiSignalStrengthMessageReply.h | 144 - .../NetworkInfoProvider/NetworkStatus.h | 93 - .../NetworkStatusChangedMessage.h | 147 - .../PropertyManager/GetPropertyMessage.h | 141 - .../PropertyManager/GetPropertyMessageReply.h | 147 - .../PropertyManager/PropertyChangedMessage.h | 144 - .../PropertyManager/PropertyState.h | 81 - .../PropertyStateChangedMessage.h | 150 - .../PropertyManager/SetPropertyMessage.h | 144 - .../modules/aasb-messaging/CMakeLists.txt | 46 - .../aasb-messaging/aac-aasb-messaging.bb | 7 - .../aasb-messaging/engine/CMakeLists.txt | 62 - .../Messaging/Messaging/ConnectionState.h | 81 - .../Messaging/ConversationsReportMessage.h | 144 - .../Message/Messaging/Messaging/ErrorCode.h | 85 - .../Messaging/Messaging/PermissionState.h | 81 - .../Messaging/SendMessageFailedMessage.h | 152 - .../Messaging/Messaging/SendMessageMessage.h | 147 - .../Messaging/SendMessageSucceededMessage.h | 141 - .../UpdateMessagesStatusFailedMessage.h | 152 - .../Messaging/UpdateMessagesStatusMessage.h | 147 - .../UpdateMessagesStatusSucceededMessage.h | 141 - .../UpdateMessagingEndpointStateMessage.h | 152 - .../Messaging/UploadConversationsMessage.h | 141 - .../modules/aasb-navigation/CMakeLists.txt | 47 - .../aasb-navigation/aac-aasb-navigation.bb | 7 - .../aasb-navigation/engine/CMakeLists.txt | 69 - .../Navigation/AlternateRouteType.h | 87 - .../Navigation/AnnounceManeuverMessage.h | 141 - .../AnnounceRoadRegulationMessage.h | 144 - .../Navigation/CancelNavigationMessage.h | 136 - .../Navigation/Navigation/ControlDisplay.h | 139 - .../Navigation/ControlDisplayMessage.h | 144 - .../Message/Navigation/Navigation/ErrorCode.h | 95 - .../Message/Navigation/Navigation/ErrorType.h | 191 - .../Message/Navigation/Navigation/EventName.h | 191 - .../Navigation/GetNavigationStateMessage.h | 136 - .../GetNavigationStateMessageReply.h | 144 - .../NavigateToPreviousWaypointMessage.h | 136 - .../Navigation/NavigationErrorMessage.h | 152 - .../Navigation/NavigationEventMessage.h | 144 - .../Navigation/Navigation/RoadRegulation.h | 83 - .../Navigation/ShowAlternativeRoutesMessage.h | 144 - .../ShowAlternativeRoutesSucceededMessage.h | 141 - .../Navigation/ShowPreviousWaypointsMessage.h | 136 - .../Navigation/StartNavigationMessage.h | 141 - .../modules/aasb-phone-control/CMakeLists.txt | 47 - .../aac-aasb-phone-control.bb | 7 - .../aasb-phone-control/engine/CMakeLists.txt | 70 - .../PhoneCallController/AnswerMessage.h | 141 - .../PhoneCallController/CallError.h | 93 - .../PhoneCallController/CallFailedMessage.h | 152 - .../PhoneCallController/CallState.h | 97 - .../CallStateChangedMessage.h | 152 - .../CallerIdReceivedMessage.h | 144 - .../CallingDeviceConfigurationProperty.h | 77 - .../PhoneCallController/ConnectionState.h | 81 - .../ConnectionStateChangedMessage.h | 144 - .../PhoneCallController/CreateCallIdMessage.h | 136 - .../CreateCallIdMessageReply.h | 144 - .../PhoneCallController/DTMFError.h | 81 - .../DeviceConfigurationUpdatedMessage.h | 141 - .../PhoneCallController/DialMessage.h | 141 - .../PhoneCallController/RedialMessage.h | 141 - .../SendDTMFFailedMessage.h | 152 - .../PhoneCallController/SendDTMFMessage.h | 141 - .../SendDTMFSucceededMessage.h | 141 - .../PhoneCallController/StopMessage.h | 141 - .../aasb-text-to-speech/CMakeLists.txt | 47 - .../aac-aasb-text-to-speech.bb | 7 - .../aasb-text-to-speech/engine/CMakeLists.txt | 56 - .../Engine/TextToSpeech/AASBTextToSpeech.h | 83 - .../TextToSpeech/GetCapabilitiesMessage.h | 141 - .../GetCapabilitiesMessageReply.h | 144 - .../PrepareSpeechCompletedMessage.h | 168 - .../TextToSpeech/PrepareSpeechFailedMessage.h | 144 - .../TextToSpeech/PrepareSpeechMessage.h | 152 - extensions/aasb/modules/aasb/CMakeLists.txt | 43 - .../aasb/modules/aasb/aac-module-aasb.bb | 7 - .../aasb/modules/aasb/engine/CMakeLists.txt | 58 - .../include/AACE/Engine/AASB/AASBEngineImpl.h | 66 - .../AACE/Engine/AASB/AASBEngineService.h | 89 - .../Engine/AASB/AASBHandlerEngineService.h | 75 - .../AACE/Engine/AASB/AASBServiceInterface.h | 46 - .../include/AACE/Engine/AASB/MessageBroker.h | 99 - .../include/AACE/Engine/AASB/StreamManager.h | 58 - .../AACE/Engine/AASB/StreamManagerInterface.h | 41 - .../AASB/Message/AASB/StartServiceMessage.h | 126 - .../AASB/Message/AASB/StopServiceMessage.h | 126 - .../aasb/engine/src/AASBEngineService.cpp | 200 - .../engine/src/AASBHandlerEngineService.cpp | 132 - .../aasb/engine/src/AASBServiceInterface.cpp | 27 - .../modules/aasb/engine/src/MessageBroker.cpp | 301 - .../modules/aasb/engine/src/StreamManager.cpp | 82 - .../aasb/modules/aasb/platform/CMakeLists.txt | 48 - .../platform/include/AACE/AASB/AASBStream.h | 87 - .../modules/aasb/platform/src/AASBStream.cpp | 24 - extensions/aasb/platforms/android/.gitignore | 78 - .../modules/aasb-address-book/CMakeLists.txt | 54 - .../modules/aasb-address-book/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../assets/meta-aac/aasb-address-book.json | 5 - .../aasb-address-book/src/main/cpp/dummy.cpp | 1 - .../android/modules/aasb-alexa/CMakeLists.txt | 53 - .../android/modules/aasb-alexa/build.gradle | 67 - .../aasb-alexa/src/main/AndroidManifest.xml | 4 - .../src/main/assets/meta-aac/aasb-alexa.json | 5 - .../modules/aasb-alexa/src/main/cpp/dummy.cpp | 1 - .../android/modules/aasb-apl/CMakeLists.txt | 53 - .../android/modules/aasb-apl/build.gradle | 67 - .../aasb-apl/src/main/AndroidManifest.xml | 4 - .../src/main/assets/meta-aac/aasb-apl.json | 5 - .../modules/aasb-apl/src/main/cpp/dummy.cpp | 1 - .../modules/aasb-car-control/CMakeLists.txt | 54 - .../modules/aasb-car-control/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../assets/meta-aac/aasb-car-control.json | 5 - .../aasb-car-control/src/main/cpp/dummy.cpp | 1 - .../android/modules/aasb-cbl/CMakeLists.txt | 53 - .../android/modules/aasb-cbl/build.gradle | 67 - .../aasb-cbl/src/main/AndroidManifest.xml | 4 - .../src/main/assets/meta-aac/aasb-cbl.json | 5 - .../modules/aasb-cbl/src/main/cpp/dummy.cpp | 1 - .../modules/aasb-connectivity/CMakeLists.txt | 55 - .../modules/aasb-connectivity/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../assets/meta-aac/aasb-connectivity.json | 5 - .../aasb-connectivity/src/main/cpp/dummy.cpp | 1 - .../android/modules/aasb-core/CMakeLists.txt | 51 - .../android/modules/aasb-core/build.gradle | 67 - .../aasb-core/src/main/AndroidManifest.xml | 4 - .../src/main/assets/meta-aac/aasb-core.json | 5 - .../modules/aasb-core/src/main/cpp/dummy.cpp | 1 - .../modules/aasb-messaging/CMakeLists.txt | 54 - .../modules/aasb-messaging/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../main/assets/meta-aac/aasb-messaging.json | 5 - .../aasb-messaging/src/main/cpp/dummy.cpp | 1 - .../modules/aasb-navigation/CMakeLists.txt | 54 - .../modules/aasb-navigation/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../main/assets/meta-aac/aasb-navigation.json | 5 - .../aasb-navigation/src/main/cpp/dummy.cpp | 1 - .../modules/aasb-phone-control/CMakeLists.txt | 54 - .../modules/aasb-phone-control/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../assets/meta-aac/aasb-phone-control.json | 5 - .../aasb-phone-control/src/main/cpp/dummy.cpp | 1 - .../aasb-text-to-speech/CMakeLists.txt | 53 - .../modules/aasb-text-to-speech/build.gradle | 67 - .../src/main/AndroidManifest.xml | 4 - .../assets/meta-aac/aasb-text-to-speech.json | 5 - .../src/main/cpp/dummy.cpp | 1 - .../android/modules/aasb/CMakeLists.txt | 54 - .../android/modules/aasb/build.gradle | 66 - .../src/main/assets/meta-aac/aace-aasb.json | 5 - extensions/bluetooth/.gitignore | 4 - extensions/bluetooth/CMakeLists.txt | 7 - .../bluetooth/aacs/android/build.gradle | 29 - .../android/modules/aacs-bluetooth/.gitignore | 2 - .../modules/aacs-bluetooth/build.gradle | 33 - .../src/main/AndroidManifest.xml | 6 - .../aacs-bluetooth.json | 5 - .../bluetooth/BluetoothModuleFactory.java | 41 - .../bluetooth/aacs/android/settings.gradle | 1 - .../modules/bluetooth/CMakeLists.txt | 33 - .../modules/bluetooth/aac-module-bluetooth.bb | 7 - .../modules/bluetooth/engine/CMakeLists.txt | 50 - .../modules/bluetooth/platform/CMakeLists.txt | 40 - .../bluetooth/platforms/android/.gitignore | 2 - .../android/modules/bluetooth/CMakeLists.txt | 55 - .../android/modules/bluetooth/build.gradle | 66 - .../main/assets/meta-aac/aace-bluetooth.json | 5 - .../bluetooth/samples/android/build.gradle | 24 - extensions/loopback-detector/README.md | 91 - extensions/loopback-detector/extra.conf | 1 - .../modules/loopback-detector/CMakeLists.txt | 32 - .../aac-module-loopback-detector.bb | 8 - .../platforms/android/.gitignore | 78 - .../modules/loopback-detector/CMakeLists.txt | 50 - .../modules/loopback-detector/build.gradle | 66 - .../meta-aac/aace-loopback-detector.json | 5 - extensions/system-audio/README.md | 200 - extensions/system-audio/extra.conf | 1 - .../modules/system-audio/CMakeLists.txt | 63 - .../system-audio/aac-module-system-audio.bb | 8 - .../system-audio/engine/CMakeLists.txt | 58 - .../engine/src/SystemAudioEngine.cpp | 0 .../engine/test/AudioInputImplTest.cpp | 97 - .../engine/test/AudioOutputImplTest.cpp | 500 - .../system-audio/engine/test/CMakeLists.txt | 44 - .../system-audio/engine/test/ThrottleTest.cpp | 84 - .../system-audio/lib/aal/CMakeLists.txt | 110 - .../system-audio/lib/aal/src/gstreamer/core.c | 362 - .../system-audio/lib/aal/src/qsa/core.c | 378 - modules/aasb/aasb/messages/aasb.yml | 12 + .../android}/src/main/AndroidManifest.xml | 0 .../src/main/assets/meta-aac/aace-aasb.json | 5 + .../cpp/include/AACE/JNI/AASB/AASBBinder.h | 0 .../include/AACE/JNI/AASB/AASBStreamBinder.h | 0 .../android}/src/main/cpp/src/AASBBinder.cpp | 0 .../src/main/cpp/src/AASBStreamBinder.cpp | 0 .../main/java/com/amazon/aace/aasb/AASB.java | 0 .../java/com/amazon/aace/aasb/AASBStream.java | 0 modules/aasb/conanfile.py | 9 + .../include/AACE/Engine/AASB/AASBEngineImpl.h | 66 + .../AACE/Engine/AASB/AASBEngineService.h | 70 + .../aasb/engine/src/AASBEngineImpl.cpp | 14 +- modules/aasb/engine/src/AASBEngineService.cpp | 116 + .../aasb/platform/include/AACE/AASB/AASB.h | 0 .../include/AACE/AASB/AASBEngineInterfaces.h | 0 .../platform/include/AACE/AASB/AASBStream.h | 31 + .../aasb/platform/src/AASB.cpp | 0 modules/address-book/.gitignore | 3 - modules/address-book/CMakeLists.txt | 56 - modules/address-book/README.md | 362 +- .../address-book/aac-module-address-book.bb | 7 - .../AASB/Engine/AddressBook/AASBAddressBook.h | 8 +- .../AASBAddressBookEngineService.h | 8 +- .../aasb/messages/AddressBook.yml | 132 + .../aasb}/src/AASBAddressBook.cpp | 8 +- .../src/AASBAddressBookEngineService.cpp | 8 +- .../android}/src/main/AndroidManifest.xml | 0 .../assets/meta-aac/aace-addressbook.json | 5 + .../AACE/JNI/AddressBook/AddressBookBinder.h | 0 .../IAddressBookEntriesFactoryBinder.h | 0 .../cpp/src/AddressBook/AddressBookBinder.cpp | 0 .../AddressBookConfigurationBinder.cpp | 0 .../IAddressBookEntriesFactoryBinder.cpp | 0 .../amazon/aace/addressbook/AddressBook.java | 7 +- .../IAddressBookEntriesFactory.java | 0 .../config/AddressBookConfiguration.java | 0 .../assets/remove_contacts.plantuml | 19 +- .../address-book/assets/remove_contacts.png | Bin 24325 -> 20029 bytes .../assets/remove_navigation_fav.plantuml | 19 +- .../assets/remove_navigation_fav.png | Bin 24580 -> 20520 bytes .../assets/upload_contacts.plantuml | 35 +- .../address-book/assets/upload_contacts.png | Bin 50109 -> 24273 bytes .../assets/upload_navigation_fav.plantuml | 37 +- .../assets/upload_navigation_fav.png | Bin 52057 -> 26223 bytes modules/address-book/conanfile.py | 9 + modules/address-book/engine/CMakeLists.txt | 65 - .../AddressBook/AddressBookServiceInterface.h | 2 + .../address-book/engine/test/CMakeLists.txt | 29 - modules/address-book/platform/CMakeLists.txt | 36 - .../include/AACE/AddressBook/AddressBook.h | 8 +- .../AddressBook/AddressBookEngineInterface.h | 2 + .../tests}/AddressBookCloudUploaderTest.cpp | 2 + modules/alexa/.gitignore | 1 - modules/alexa/CMakeLists.txt | 62 - modules/alexa/README.md | 1085 +- modules/alexa/aac-module-alexa.bb | 7 - .../include/AASB/Engine/Alexa/AASBAlerts.h | 8 +- .../AASB/Engine/Alexa/AASBAlexaClient.h | 8 +- .../Engine/Alexa/AASBAlexaEngineService.h | 10 +- .../AASB/Engine/Alexa/AASBAlexaSpeaker.h | 8 +- .../AASB/Engine/Alexa/AASBAudioPlayer.h | 8 +- .../AASB/Engine/Alexa/AASBAuthProvider.h | 8 +- .../AASB/Engine/Alexa/AASBDeviceSetup.h | 8 +- .../AASB/Engine/Alexa/AASBDoNotDisturb.h | 8 +- .../Engine/Alexa/AASBEqualizerController.h | 8 +- .../Engine/Alexa/AASBExternalMediaAdapter.h | 8 +- .../AASB/Engine/Alexa/AASBGlobalPreset.h | 8 +- .../AASB/Engine/Alexa/AASBLocalMediaSource.h | 8 +- .../Engine/Alexa/AASBMediaPlaybackRequestor.h | 49 + .../AASB/Engine/Alexa/AASBNotifications.h | 8 +- .../Engine/Alexa/AASBPlaybackController.h | 6 +- .../AASB/Engine/Alexa/AASBSpeechRecognizer.h | 8 +- .../AASB/Engine/Alexa/AASBSpeechSynthesizer.h | 2 +- .../AASB/Engine/Alexa/AASBTemplateRuntime.h | 8 +- .../ExternalMediaAdapter/ValidationData.h | 0 modules/alexa/aasb/messages/Alerts.yml | 73 + modules/alexa/aasb/messages/AlexaClient.yml | 109 + modules/alexa/aasb/messages/AlexaSpeaker.yml | 75 + modules/alexa/aasb/messages/AudioPlayer.yml | 45 + modules/alexa/aasb/messages/AuthProvider.yml | 77 + modules/alexa/aasb/messages/DeviceSetup.yml | 26 + modules/alexa/aasb/messages/DoNotDisturb.yml | 21 + .../aasb/messages/EqualizerController.yml | 81 + .../aasb/messages/ExternalMediaAdapter.yml | 491 + modules/alexa/aasb/messages/GlobalPreset.yml | 13 + .../alexa/aasb/messages/LocalMediaSource.yml | 309 + .../aasb/messages/MediaPlaybackRequestor.yml | 49 + modules/alexa/aasb/messages/Notifications.yml | 27 + .../aasb/messages/PlaybackController.yml | 60 + .../alexa/aasb/messages/SpeechRecognizer.yml | 59 + .../alexa/aasb/messages/TemplateRuntime.yml | 60 + .../alexa/aasb}/src/AASBAlerts.cpp | 8 +- .../alexa/aasb}/src/AASBAlexaClient.cpp | 16 +- .../aasb}/src/AASBAlexaEngineService.cpp | 30 +- .../alexa/aasb}/src/AASBAlexaSpeaker.cpp | 8 +- .../alexa/aasb}/src/AASBAudioPlayer.cpp | 18 +- .../alexa/aasb}/src/AASBAuthProvider.cpp | 8 +- .../alexa/aasb}/src/AASBDeviceSetup.cpp | 6 +- .../alexa/aasb}/src/AASBDoNotDisturb.cpp | 6 +- .../aasb}/src/AASBEqualizerController.cpp | 9 +- .../aasb}/src/AASBExternalMediaAdapter.cpp | 32 +- .../alexa/aasb}/src/AASBGlobalPreset.cpp | 6 +- .../alexa/aasb}/src/AASBLocalMediaSource.cpp | 11 +- .../aasb/src/AASBMediaPlaybackRequestor.cpp | 99 + .../alexa/aasb}/src/AASBNotifications.cpp | 6 +- .../aasb}/src/AASBPlaybackController.cpp | 6 +- .../alexa/aasb}/src/AASBSpeechRecognizer.cpp | 6 +- .../alexa/aasb}/src/AASBSpeechSynthesizer.cpp | 0 .../alexa/aasb}/src/AASBTemplateRuntime.cpp | 12 +- .../android}/src/main/AndroidManifest.xml | 0 .../src/main/assets/meta-aac/aace-alexa.json | 5 + .../cpp/include/AACE/JNI/Alexa/AlertsBinder.h | 0 .../AACE/JNI/Alexa/AlexaClientBinder.h | 0 .../AACE/JNI/Alexa/AlexaConfigurationBinder.h | 0 .../AACE/JNI/Alexa/AlexaSpeakerBinder.h | 0 .../AACE/JNI/Alexa/AudioPlayerBinder.h | 0 .../AACE/JNI/Alexa/AuthProviderBinder.h | 0 .../AACE/JNI/Alexa/DeviceSetupBinder.h | 0 .../AACE/JNI/Alexa/DoNotDisturbBinder.h | 0 .../JNI/Alexa/EqualizerControllerBinder.h | 0 .../JNI/Alexa/ExternalMediaAdapterBinder.h | 0 .../AACE/JNI/Alexa/GlobalPresetBinder.h | 0 .../AACE/JNI/Alexa/LocalMediaSourceBinder.h | 0 .../JNI/Alexa/MediaPlaybackRequestorBinder.h | 103 + .../AACE/JNI/Alexa/NotificationsBinder.h | 0 .../AACE/JNI/Alexa/PlaybackControllerBinder.h | 0 .../AACE/JNI/Alexa/SpeechRecognizerBinder.h | 0 .../AACE/JNI/Alexa/SpeechSynthesizerBinder.h | 0 .../AACE/JNI/Alexa/TemplateRuntimeBinder.h | 0 .../src/main/cpp/src/Alexa/AlertsBinder.cpp | 0 .../main/cpp/src/Alexa/AlexaClientBinder.cpp | 0 .../src/Alexa/AlexaConfigurationBinder.cpp | 27 +- .../main/cpp/src/Alexa/AlexaSpeakerBinder.cpp | 0 .../main/cpp/src/Alexa/AudioPlayerBinder.cpp | 0 .../main/cpp/src/Alexa/AuthProviderBinder.cpp | 0 .../main/cpp/src/Alexa/DeviceSetupBinder.cpp | 0 .../main/cpp/src/Alexa/DoNotDisturbBinder.cpp | 0 .../src/Alexa/EqualizerControllerBinder.cpp | 0 .../src/Alexa/ExternalMediaAdapterBinder.cpp | 0 .../main/cpp/src/Alexa/GlobalPresetBinder.cpp | 0 .../cpp/src/Alexa/LocalMediaSourceBinder.cpp | 0 .../Alexa/MediaPlaybackRequestorBinder.cpp | 104 + .../cpp/src/Alexa/NotificationsBinder.cpp | 0 .../src/Alexa/PlaybackControllerBinder.cpp | 0 .../cpp/src/Alexa/SpeechRecognizerBinder.cpp | 0 .../cpp/src/Alexa/SpeechSynthesizerBinder.cpp | 0 .../cpp/src/Alexa/TemplateRuntimeBinder.cpp | 0 .../java/com/amazon/aace/alexa/Alerts.java | 7 +- .../com/amazon/aace/alexa/AlexaClient.java | 7 +- .../amazon/aace/alexa/AlexaProperties.java | 0 .../com/amazon/aace/alexa/AlexaSpeaker.java | 7 +- .../com/amazon/aace/alexa/AudioPlayer.java | 7 +- .../com/amazon/aace/alexa/AuthProvider.java | 7 +- .../com/amazon/aace/alexa/DeviceSetup.java | 5 + .../com/amazon/aace/alexa/DoNotDisturb.java | 7 +- .../aace/alexa/EqualizerController.java | 7 +- .../aace/alexa/ExternalMediaAdapter.java | 7 +- .../com/amazon/aace/alexa/GlobalPreset.java | 9 +- .../amazon/aace/alexa/LocalMediaSource.java | 7 +- .../aace/alexa/MediaPlaybackRequestor.java | 159 + .../com/amazon/aace/alexa/Notifications.java | 7 +- .../amazon/aace/alexa/PlaybackController.java | 178 + .../amazon/aace/alexa/SpeechRecognizer.java | 7 +- .../amazon/aace/alexa/SpeechSynthesizer.java | 7 +- .../amazon/aace/alexa/TemplateRuntime.java | 7 +- .../aace/alexa/config/AlexaConfiguration.java | 95 +- ...plete-interaction-tap-to-talk-sequence.svg | 166 + ...-interaction-tap-to-talk-sequence.plantuml | 160 + modules/alexa/cmake/FindAVS.cmake | 109 - modules/alexa/cmake/aac-alexa-module.cmake | 4 + modules/alexa/conanfile.py | 16 + modules/alexa/engine/CMakeLists.txt | 156 - .../AACE/Engine/Alexa/AlertsEngineImpl.h | 4 +- .../Engine/Alexa/AlexaComponentInterface.h | 6 +- .../AACE/Engine/Alexa/AlexaEngineService.h | 55 +- .../Engine/Alexa/AudioChannelEngineImpl.h | 70 +- .../Engine/Alexa/AuthProviderEngineImpl.h | 1 - .../AACE/Engine/Alexa/AuthorizationManager.h | 17 +- .../AACE/Engine/Alexa/ChannelVolumeManager.h | 129 + .../Engine/Alexa/DeviceSettingsDelegate.h | 2 +- .../AACE/Engine/Alexa/DeviceSetupEngineImpl.h | 21 +- .../Alexa/DiscoveredPlayerSenderInterface.h | 2 + .../Engine/Alexa/DoNotDisturbEngineImpl.h | 4 +- .../AACE/Engine/Alexa/DuckingInterface.h | 49 + .../Alexa/EqualizerControllerEngineImpl.h | 6 +- .../Alexa/ExternalMediaPlayerEngineImpl.h | 3 +- .../AACE/Engine/Alexa/LocaleAssetsManager.h | 34 +- .../Engine/Alexa/MediaPlaybackRequestor.h | 114 + .../Alexa/MediaPlaybackRequestorEngineImpl.h | 90 + .../Engine/Alexa/NotificationsEngineImpl.h | 4 +- .../Engine/Alexa/SpeechRecognizerEngineImpl.h | 76 +- .../AACE/Engine/Alexa/SystemSoundPlayer.h | 1 + .../Engine/Alexa/TemplateRuntimeEngineImpl.h | 17 +- modules/alexa/engine/src/AdapterUtils.cpp | 6 +- modules/alexa/engine/src/AlertsEngineImpl.cpp | 4 +- .../engine/src/AlexaAuthorizationProvider.cpp | 3 +- .../engine/src/AlexaConfigurationImpl.cpp | 22 +- .../alexa/engine/src/AlexaEngineService.cpp | 268 +- modules/alexa/engine/src/AlexaMetricSink.cpp | 2 +- .../engine/src/AudioChannelEngineImpl.cpp | 203 +- .../engine/src/AuthProviderEngineImpl.cpp | 17 +- .../alexa/engine/src/AuthorizationManager.cpp | 13 +- .../alexa/engine/src/ChannelVolumeManager.cpp | 201 + .../engine/src/DeviceSettingsDelegate.cpp | 2 +- .../engine/src/DeviceSetupEngineImpl.cpp | 65 +- .../engine/src/DoNotDisturbEngineImpl.cpp | 4 +- .../src/EqualizerControllerEngineImpl.cpp | 4 +- .../src/ExternalMediaAdapterHandler.cpp | 2 +- .../alexa/engine/src/ExternalMediaPlayer.cpp | 104 +- .../src/ExternalMediaPlayerEngineImpl.cpp | 3 +- .../alexa/engine/src/LocaleAssetsManager.cpp | 46 +- .../engine/src/MediaPlaybackRequestor.cpp | 168 + .../src/MediaPlaybackRequestorEngineImpl.cpp | 157 + .../engine/src/NotificationsEngineImpl.cpp | 15 +- .../engine/src/SpeechRecognizerEngineImpl.cpp | 67 +- .../alexa/engine/src/SystemSoundPlayer.cpp | 3 + .../engine/src/TemplateRuntimeEngineImpl.cpp | 22 +- modules/alexa/engine/test/CMakeLists.txt | 169 - ...aInterfaceMessageSenderInternalInterface.h | 61 - .../AACE/Test/AVS/MockAttachmentManager.h | 50 - .../AACE/Test/AVS/MockCustomerDataManager.h | 37 - ...MockEndpointRegistrationManagerInterface.h | 50 - .../Test/Alexa/AlexaMockComponentFactory.h | 242 - modules/alexa/engine/test/src/main.cpp | 6 - modules/alexa/platform/CMakeLists.txt | 2 + .../platform/include/AACE/Alexa/Alerts.h | 7 +- .../platform/include/AACE/Alexa/AlexaClient.h | 7 +- .../include/AACE/Alexa/AlexaConfiguration.h | 43 +- .../AACE/Alexa/AlexaEngineInterfaces.h | 105 + .../include/AACE/Alexa/AlexaSpeaker.h | 7 +- .../platform/include/AACE/Alexa/AudioPlayer.h | 7 +- .../include/AACE/Alexa/AuthProvider.h | 7 +- .../platform/include/AACE/Alexa/DeviceSetup.h | 5 + .../include/AACE/Alexa/DoNotDisturb.h | 7 +- .../include/AACE/Alexa/EqualizerController.h | 7 +- .../include/AACE/Alexa/ExternalMediaAdapter.h | 8 +- .../include/AACE/Alexa/GlobalPreset.h | 10 +- .../include/AACE/Alexa/LocalMediaSource.h | 7 +- .../AACE/Alexa/MediaPlaybackRequestor.h | 102 + .../include/AACE/Alexa/Notifications.h | 7 +- .../include/AACE/Alexa/PlaybackController.h | 7 +- .../include/AACE/Alexa/SpeechRecognizer.h | 7 +- .../include/AACE/Alexa/SpeechSynthesizer.h | 7 +- .../include/AACE/Alexa/TemplateRuntime.h | 7 +- .../platform/src/MediaPlaybackRequestor.cpp | 39 + ...aInterfaceMessageSenderInternalInterface.h | 81 + .../Test/Unit/AVS/MockAttachmentManager.h | 52 + .../Test/Unit}/AVS/MockAudioPlayerInterface.h | 2 + .../AVS/MockAudioPlayerObserverInterface.h | 2 + .../Unit}/AVS/MockAuthDelegateInterface.h | 8 +- .../Unit}/AVS/MockConnectionStatusObserver.h | 8 +- .../Test/Unit/AVS/MockCustomerDataManager.h | 39 + .../Test/Unit/AVS}/MockDeviceSettingStorage.h | 0 .../Unit}/AVS/MockDeviceSettingsManager.h | 8 +- ...MockEndpointRegistrationManagerInterface.h | 59 + .../MockInternetConnectionMonitorInterface.h | 8 +- .../AACE/Test/Unit}/AVS/MockMessageObserver.h | 8 +- .../AACE/Test/Unit}/AVS/MockMessageRouter.h | 8 +- .../AACE/Test/Unit}/AVS/MockMessageStorage.h | 8 +- .../AACE/Test/Unit}/AVS/MockMetricRecorder.h | 8 +- .../MockNotificationsAudioFactoryInterface.h | 8 +- ...ckRenderPlayerInfoCardsProviderInterface.h | 8 +- .../AACE/Test/Unit}/AVS/MockSpeakerManager.h | 0 .../Unit}/AVS/MockSpeechConfirmationSetting.h | 8 +- .../AACE/Test/Unit}/AVS/MockSpeechEncoder.h | 8 +- .../AVS/MockSystemSoundPlayerInterface.h | 8 +- .../AVS/MockWakeWordConfirmationSetting.h | 8 +- .../Test/Unit}/AVS/MockWakeWordsSetting.h | 8 +- .../Unit/Alexa/AlexaMockComponentFactory.h | 244 + .../AACE/Test/Unit}/Alexa/AlexaTestHelper.h | 8 +- .../AACE/Test/Unit}/Alexa/MockAlerts.h | 8 +- .../AACE/Test/Unit}/Alexa/MockAlexaClient.h | 8 +- .../AACE/Test/Unit}/Alexa/MockAudioPlayer.h | 8 +- .../AACE/Test/Unit}/Alexa/MockAuthProvider.h | 8 +- .../Unit}/Alexa/MockAuthorizationManager.h | 8 +- .../Unit}/Alexa/MockDeviceSettingsDelegate.h | 8 +- .../AACE/Test/Unit}/Alexa/MockDeviceSetup.h | 8 +- .../Test/Unit}/Alexa/MockInitiatorVerifier.h | 8 +- .../AACE/Test/Unit}/Alexa/MockNotifications.h | 8 +- .../Test/Unit}/Alexa/MockPlaybackController.h | 8 +- .../Test/Unit}/Alexa/MockSpeechRecognizer.h | 8 +- .../Test/Unit}/Alexa/MockSpeechSynthesizer.h | 8 +- .../Test/Unit}/Alexa/MockTemplateRuntime.h | 8 +- .../Unit}/Alexa/MockWakewordEngineAdapter.h | 8 +- .../src/AlexaMockComponentFactory.cpp | 114 +- .../unit/framework}/src/AlexaTestHelper.cpp | 8 +- .../unit/framework}/src/StubMiscStorage.cpp | 0 .../unit/tests}/AlertsEngineImplTest.cpp | 12 +- .../tests}/AlexaAuthorizationProviderTest.cpp | 10 +- .../unit/tests}/AlexaClientEngineImplTest.cpp | 4 +- .../tests}/AlexaConfigurationImplTest.cpp | 21 + .../tests}/AlexaEngineClientObserverTest.cpp | 0 .../unit/tests}/AlexaEngineLoggerTest.cpp | 4 +- .../unit/tests}/AudioPlayerEngineImplTest.cpp | 12 +- .../tests}/AuthProviderEngineImplTest.cpp | 22 +- .../unit/tests}/AuthorizationManagerTest.cpp | 28 +- .../unit/tests}/DeviceSetupEngineImplTest.cpp | 14 +- .../tests}/DoNotDisturbEngineImplTest.cpp | 12 +- .../tests}/NotificationsEngineImplTest.cpp | 12 +- .../PlaybackControllerEngineImplTest.cpp | 4 +- .../tests}/SpeechRecognizerEngineImplTest.cpp | 93 +- .../SpeechSynthesizerEngineImplTest.cpp | 12 +- .../tests}/TemplateRuntimeEngineImplTest.cpp | 17 +- modules/apl/CMakeLists.txt | 55 - modules/apl/README.md | 173 +- modules/apl/aac-module-apl.bb | 7 - .../aasb}/include/AASB/Engine/APL/AASBAPL.h | 10 +- .../AASB/Engine/APL/AASBAPLEngineService.h | 8 +- modules/apl/aasb/messages/APL.yml | 174 + .../apl/aasb}/src/AASBAPL.cpp | 78 +- .../apl/aasb}/src/AASBAPLEngineService.cpp | 8 +- .../apl/android}/src/main/AndroidManifest.xml | 0 .../src/main/assets/meta-aac/aace-apl.json | 5 + .../main/cpp/include/AACE/JNI/APL/APLBinder.h | 1 + .../AACE/JNI/APL/APLConfigurationBinder.h | 0 .../src/main/cpp/src/APL/APLBinder.cpp | 28 + .../cpp/src/APL/APLConfigurationBinder.cpp | 0 .../main/java/com/amazon/aace/apl/APL.java | 45 + .../aace/apl/config/APLConfiguration.java | 0 modules/apl/assets/aac-apl-general-flow.png | Bin 0 -> 49047 bytes .../aac-apl-platform-properties.plantuml | 41 + .../assets/aac-apl-render-document.plantuml | 47 + .../aac-apl-set-platform-properties.png | Bin 0 -> 35862 bytes modules/apl/conanfile.py | 13 + modules/apl/engine/CMakeLists.txt | 72 - .../include/AACE/Engine/APL/APLEngineImpl.h | 35 +- .../Engine/APL/APLRuntimePropertyGenerator.h | 45 + modules/apl/engine/src/APLEngineImpl.cpp | 71 +- modules/apl/engine/src/APLEngineService.cpp | 4 + .../src/APLRuntimePropertyGenerator.cpp | 89 + modules/apl/platform/CMakeLists.txt | 36 - modules/apl/platform/include/AACE/APL/APL.h | 48 + .../include/AACE/APL/APLEngineInterface.h | 3 + modules/apl/platform/src/APL.cpp | 6 + {extensions => modules}/bluetooth/README.md | 0 .../android}/src/main/AndroidManifest.xml | 0 .../main/assets/meta-aac/aace-bluetooth.json | 5 + .../JNI/Bluetooth/BluetoothProviderBinder.h | 0 .../Bluetooth/BluetoothServerSocketBinder.h | 0 .../JNI/Bluetooth/BluetoothSocketBinder.h | 0 .../AACE/JNI/Bluetooth/GATTServerBinder.h | 0 .../src/Bluetooth/BluetoothProviderBinder.cpp | 0 .../Bluetooth/BluetoothServerSocketBinder.cpp | 0 .../src/Bluetooth/BluetoothSocketBinder.cpp | 0 .../cpp/src/Bluetooth/GATTServerBinder.cpp | 0 .../aace/bluetooth/BluetoothProvider.java | 0 .../aace/bluetooth/BluetoothServerSocket.java | 0 .../aace/bluetooth/BluetoothSocket.java | 0 .../com/amazon/aace/bluetooth/GATTServer.java | 0 modules/bluetooth/assets/ble.plantuml | 36 + modules/bluetooth/assets/ble.png | Bin 0 -> 38498 bytes .../assets/bluetooth_classic.plantuml | 41 + .../bluetooth/assets/bluetooth_classic.png | Bin 0 -> 44980 bytes modules/bluetooth/conanfile.py | 9 + .../Engine/Bluetooth/BluetoothEngineService.h | 0 .../Bluetooth/BluetoothServiceInterface.h | 0 .../Engine/Bluetooth/GATTCharacteristic.h | 0 .../AACE/Engine/Bluetooth/GATTDescriptor.h | 0 .../Engine/Bluetooth/GATTServerEngineImpl.h | 0 .../Engine/Bluetooth/GATTServerInterface.h | 0 .../AACE/Engine/Bluetooth/GATTService.h | 0 .../engine/src/BluetoothEngineService.cpp | 4 +- .../bluetooth/engine/src/GATTDescriptor.cpp | 0 .../engine/src/GATTServerEngineImpl.cpp | 0 .../bluetooth/engine/src/GATTService.cpp | 0 .../Bluetooth/BluetoothEngineInterfaces.h | 2 + .../AACE/Bluetooth/BluetoothProvider.h | 0 .../AACE/Bluetooth/BluetoothServerSocket.h | 0 .../include/AACE/Bluetooth/BluetoothSocket.h | 0 .../include/AACE/Bluetooth/ByteArray.h | 0 .../include/AACE/Bluetooth/GATTServer.h | 0 .../platform/src/BluetoothProvider.cpp | 0 .../bluetooth/platform/src/ByteArray.cpp | 0 .../bluetooth/platform/src/GATTServer.cpp | 0 .../bluetooth/samples/android/.gitignore | 0 .../bluetooth/samples/android/build.gradle | 24 + .../modules/sample-bluetooth}/.gitignore | 0 .../modules/sample-bluetooth/build.gradle | 0 .../sample-bluetooth/gradle.properties | 0 .../sample-bluetooth}/proguard-rules.pro | 0 .../src/main/AndroidManifest.xml | 0 .../assets/sample-app/sample-bluetooth.json | 0 .../bluetooth/BluetoothModuleFactory.java | 0 .../bluetooth/BluetoothProviderHandler.java | 0 .../BluetoothServerSocketHandler.java | 0 .../bluetooth/BluetoothSocketHandler.java | 0 .../bluetooth/GATTServerHandler.java | 0 .../src/main/res/values/strings.xml | 0 .../bluetooth/samples/android/settings.gradle | 0 modules/car-control/.gitignore | 3 - modules/car-control/CMakeLists.txt | 57 - modules/car-control/README.md | 2065 +- modules/car-control/aac-module-car-control.bb | 7 - .../AASB/Engine/CarControl/AASBCarControl.h | 8 +- .../CarControl/AASBCarControlEngineService.h | 10 +- .../car-control/aasb/messages/CarControl.yml | 143 + .../car-control/aasb}/src/AASBCarControl.cpp | 18 +- .../aasb}/src/AASBCarControlEngineService.cpp | 14 +- .../android}/src/main/AndroidManifest.xml | 0 .../assets/meta-aac/aace-car-control.json | 5 + .../AACE/JNI/CarControl/CarControlBinder.h | 0 .../cpp/src/CarControl/CarControlBinder.cpp | 0 .../CarControlConfigurationBinder.cpp | 0 .../amazon/aace/carControl/CarControl.java | 7 +- .../aace/carControl/CarControlAssets.java | 0 .../carControl/CarControlConfiguration.java | 0 .../adjusting_mode_of_a_setting.plantuml | 45 + .../assets/adjusting_mode_of_a_setting.png | Bin 0 -> 29596 bytes .../adjusting_value_of_a_setting.plantuml | 45 + .../assets/adjusting_value_of_a_setting.png | Bin 0 -> 30030 bytes .../assets/setting_mode_of_a_setting.plantuml | 45 + .../assets/setting_mode_of_a_setting.png | Bin 0 -> 28043 bytes .../setting_value_of_a_setting.plantuml | 45 + .../assets/setting_value_of_a_setting.png | Bin 0 -> 29274 bytes .../assets/turning_off_endpoint.plantuml | 45 + .../assets/turning_off_endpoint.png | Bin 0 -> 27397 bytes ...rning_off_toggle_state_of_setting.plantuml | 45 + .../turning_off_toggle_state_of_setting.png | Bin 0 -> 28347 bytes .../assets/turning_on_endpoint.plantuml | 45 + .../assets/turning_on_endpoint.png | Bin 0 -> 27276 bytes ...urning_on_toggle_state_of_setting.plantuml | 45 + .../turning_on_toggle_state_of_setting.png | Bin 0 -> 28246 bytes modules/car-control/conanfile.py | 9 + modules/car-control/engine/CMakeLists.txt | 92 - .../CarControl/CarControlServiceInterface.h | 2 + .../car-control/engine/test/CMakeLists.txt | 24 - modules/car-control/platform/CMakeLists.txt | 40 - .../include/AACE/CarControl/CarControl.h | 7 +- modules/cbl/CMakeLists.txt | 55 - modules/cbl/README.md | 207 +- modules/cbl/aac-module-cbl.bb | 7 - .../aasb}/include/AASB/Engine/CBL/AASBCBL.h | 13 +- .../AASB/Engine/CBL/AASBCBLEngineService.h | 44 + modules/cbl/aasb/messages/CBL.yml | 93 + .../cbl/aasb}/src/AASBCBL.cpp | 31 +- .../cbl/aasb}/src/AASBCBLEngineService.cpp | 12 +- .../cbl/android}/src/main/AndroidManifest.xml | 0 .../src/main/assets/meta-aac/aace-cbl.json | 5 + .../main/cpp/include/AACE/JNI/CBL/CBLBinder.h | 0 .../src/main/cpp/src/CBL/CBLBinder.cpp | 0 .../cpp/src/CBL/CBLConfigurationBinder.cpp | 0 .../main/java/com/amazon/aace/cbl/CBL.java | 7 +- .../aace/cbl/config/CBLConfiguration.java | 0 modules/cbl/conanfile.py | 9 + modules/cbl/engine/CMakeLists.txt | 61 - .../engine/src/CBLAuthorizationProvider.cpp | 2 + modules/cbl/engine/test/CMakeLists.txt | 29 - modules/cbl/platform/CMakeLists.txt | 36 - modules/cbl/platform/include/AACE/CBL/CBL.h | 7 +- .../include/AACE/CBL/CBLEngineInterface.h | 2 + .../tests}/CBLAuthorizationProviderTest.cpp | 8 +- modules/connectivity/CMakeLists.txt | 54 - modules/connectivity/README.md | 224 +- .../connectivity/aac-module-connectivity.bb | 7 - .../Connectivity/AASBAlexaConnectivity.h | 8 +- .../AASBConnectivityEngineService.h | 8 +- .../aasb/messages/AlexaConnectivity.yml | 46 + .../aasb}/src/AASBAlexaConnectivity.cpp | 27 +- .../src/AASBConnectivityEngineService.cpp | 14 +- .../android}/src/main/AndroidManifest.xml | 0 .../assets/meta-aac/aace-connectivity.json | 5 + .../Connectivity/AlexaConnectivityBinder.h | 0 .../Connectivity/AlexaConnectivityBinder.cpp | 0 .../aace/connectivity/AlexaConnectivity.java | 5 + .../Connectivity-Sequence-CloudAskReport.png | Bin 43591 -> 21281 bytes .../Connectivity-Sequence-CloudAskReport.puml | 52 +- .../Connectivity-Sequence-ConnectCloud.png | Bin 46817 -> 0 bytes .../Connectivity-Sequence-ConnectCloud.puml | 36 - .../Connectivity-Sequence-DeviceDiscovery.png | Bin 32293 -> 13800 bytes ...Connectivity-Sequence-DeviceDiscovery.puml | 41 +- ...ctivity-Sequence-sendConnectivityEvent.png | Bin 72256 -> 42912 bytes ...tivity-Sequence-sendConnectivityEvent.puml | 65 +- modules/connectivity/conanfile.py | 9 + modules/connectivity/engine/CMakeLists.txt | 79 - .../connectivity/engine/test/CMakeLists.txt | 73 - modules/connectivity/platform/CMakeLists.txt | 39 - .../AACE/Connectivity/AlexaConnectivity.h | 5 + .../AlexaConnectivityEngineInterface.h | 2 + .../Connectivity/MockAlexaConnectivity.h | 8 +- .../AlexaConnectivityEngineImplTest.cpp | 18 +- modules/core/.gitignore | 1 - modules/core/AUDIO.md | 395 + modules/core/AUTHORIZATION.md | 212 + modules/core/CMakeLists.txt | 61 - modules/core/README.md | 952 +- modules/core/RUNTIME_PROPERTIES.md | 145 + modules/core/aac-module-core.bb | 10 - .../Engine/Audio/AASBAudioEngineService.h | 8 +- .../AASB/Engine/Audio/AASBAudioInput.h | 95 + .../Engine/Audio/AASBAudioInputProvider.h | 59 + .../AASB/Engine/Audio/AASBAudioOutput.h | 101 + .../Engine/Audio/AASBAudioOutputProvider.h | 56 + .../Engine/Authorization/AASBAuthorization.h | 11 +- .../AASBAuthorizationEngineService.h | 8 +- .../AASB/Engine/DeviceUsage/AASBDeviceUsage.h | 8 +- .../AASBDeviceUsageEngineService.h | 8 +- .../Location/AASBLocationEngineService.h | 8 +- .../Engine/Location/AASBLocationProvider.h | 8 +- .../Engine/Network/AASBNetworkEngineService.h | 8 +- .../Engine/Network/AASBNetworkInfoProvider.h | 8 +- .../PropertyManager/AASBPropertyManager.h | 8 +- .../AASBPropertyManagerEngineService.h | 8 +- .../aasb/include/AASB/Utils/StringUtils.h | 35 + modules/core/aasb/include/AASB/Utils/UUID.h | 33 + modules/core/aasb/messages/AudioInput.yml | 35 + modules/core/aasb/messages/AudioOutput.yml | 322 + modules/core/aasb/messages/Authorization.yml | 100 + modules/core/aasb/messages/DeviceUsage.yml | 12 + .../core/aasb/messages/LocationProvider.yml | 55 + .../aasb/messages/NetworkInfoProvider.yml | 47 + .../core/aasb/messages/PropertyManager.yml | 59 + .../src/Audio/AASBAudioEngineService.cpp | 6 +- .../core/aasb}/src/Audio/AASBAudioInput.cpp | 14 +- .../src/Audio/AASBAudioInputProvider.cpp | 8 +- .../core/aasb}/src/Audio/AASBAudioOutput.cpp | 114 +- .../src/Audio/AASBAudioOutputProvider.cpp | 8 +- .../src/Authorization/AASBAuthorization.cpp | 60 +- .../AASBAuthorizationEngineService.cpp | 8 +- .../aasb}/src/DeviceUsage/AASBDeviceUsage.cpp | 6 +- .../AASBDeviceUsageEngineService.cpp | 11 +- .../Location/AASBLocationEngineService.cpp | 8 +- .../src/Location/AASBLocationProvider.cpp | 8 +- .../src/Network/AASBNetworkEngineService.cpp | 8 +- .../src/Network/AASBNetworkInfoProvider.cpp | 8 +- .../PropertyManager/AASBPropertyManager.cpp | 9 +- .../AASBPropertyManagerEngineService.cpp | 8 +- .../android}/src/main/AndroidManifest.xml | 0 .../src/main/assets/meta-aac/aace-core.json | 5 + .../include/AACE/JNI/Audio/AudioInputBinder.h | 0 .../AACE/JNI/Audio/AudioInputProviderBinder.h | 0 .../AACE/JNI/Audio/AudioOutputBinder.h | 23 + .../JNI/Audio/AudioOutputProviderBinder.h | 0 .../AACE/JNI/Audio/AudioStreamBinder.h | 0 .../JNI/Authorization/AuthorizationBinder.h | 0 .../cpp/include/AACE/JNI/Core/EngineBinder.h | 0 .../AACE/JNI/Core/EngineConfigurationBinder.h | 0 .../AACE/JNI/Core/MessageBrokerBinder.h | 49 + .../AACE/JNI/Core/MessageStreamBinder.h | 67 + .../cpp/include/AACE/JNI/Core/NativeLib.h | 0 .../AACE/JNI/Core/PlatformInterfaceBinder.h | 0 .../AACE/JNI/DeviceUsage/DeviceUsageBinder.h | 0 .../JNI/Location/LocationProviderBinder.h | 0 .../include/AACE/JNI/Logger/LoggerBinder.h | 0 .../AACE/JNI/Metrics/MetricsUploaderBinder.h | 0 .../cpp/include/AACE/JNI/Native/GlobalRef.h | 0 .../cpp/include/AACE/JNI/Native/JavaArray.h | 0 .../cpp/include/AACE/JNI/Native/JavaClass.h | 0 .../cpp/include/AACE/JNI/Native/JavaEnum.h | 0 .../cpp/include/AACE/JNI/Native/JavaField.h | 0 .../cpp/include/AACE/JNI/Native/JavaMethod.h | 0 .../cpp/include/AACE/JNI/Native/JavaObject.h | 0 .../cpp/include/AACE/JNI/Native/JavaString.h | 0 .../include/AACE/JNI/Native/NativeMacros.h | 3 +- .../include/AACE/JNI/Native/ThreadContext.h | 0 .../JNI/Network/NetworkInfoProviderBinder.h | 0 .../PropertyManager/PropertyManagerBinder.h | 0 .../JNI/Vehicle/VehicleConfigurationBinder.h | 0 .../main/cpp/src/Audio/AudioInputBinder.cpp | 0 .../src/Audio/AudioInputProviderBinder.cpp | 0 .../main/cpp/src/Audio/AudioOutputBinder.cpp | 47 + .../src/Audio/AudioOutputProviderBinder.cpp | 0 .../main/cpp/src/Audio/AudioStreamBinder.cpp | 0 .../src/Authorization/AuthorizationBinder.cpp | 0 .../cpp/src/DeviceUsage/DeviceUsageBinder.cpp | 0 .../src/main/cpp/src/EngineBinder.cpp | 29 + .../cpp/src/EngineConfigurationBinder.cpp | 0 .../src/Location/LocationProviderBinder.cpp | 0 .../src/main/cpp/src/Logger/LoggerBinder.cpp | 0 .../src/Logger/LoggerConfigurationBinder.cpp | 0 .../src/main/cpp/src/MessageBrokerBinder.cpp | 134 + .../src/main/cpp/src/MessageStreamBinder.cpp | 115 + .../cpp/src/Metrics/MetricsUploaderBinder.cpp | 0 .../src/main/cpp/src/Native/JavaArray.cpp | 0 .../src/main/cpp/src/Native/JavaClass.cpp | 0 .../src/main/cpp/src/Native/JavaField.cpp | 3 - .../src/main/cpp/src/Native/JavaMethod.cpp | 3 - .../src/main/cpp/src/Native/JavaObject.cpp | 0 .../src/main/cpp/src/Native/JavaString.cpp | 0 .../src/main/cpp/src/Native/ThreadContext.cpp | 0 .../src/Network/NetworkInfoProviderBinder.cpp | 0 .../main/cpp/src/PlatformInterfaceBinder.cpp | 3 - .../PropertyManager/PropertyManagerBinder.cpp | 0 .../Storage/StorageConfigurationBinder.cpp | 0 .../Vehicle/VehicleConfigurationBinder.cpp | 0 .../com/amazon/aace/audio/AudioFormat.java | 0 .../com/amazon/aace/audio/AudioInput.java | 0 .../amazon/aace/audio/AudioInputProvider.java | 7 +- .../com/amazon/aace/audio/AudioOutput.java | 69 + .../aace/audio/AudioOutputProvider.java | 7 +- .../com/amazon/aace/audio/AudioStream.java | 0 .../aace/authorization/Authorization.java | 7 +- .../com/amazon/aace/core/CoreProperties.java | 0 .../java/com/amazon/aace/core/Engine.java | 27 +- .../com/amazon/aace/core/MessageBroker.java | 55 + .../com/amazon/aace/core/MessageStream.java | 136 + .../java/com/amazon/aace/core/NativeRef.java | 0 .../amazon/aace/core/PlatformInterface.java | 0 .../aace/core/config/ConfigurationFile.java | 0 .../aace/core/config/EngineConfiguration.java | 0 .../aace/core/config/StreamConfiguration.java | 0 .../amazon/aace/deviceusage/DeviceUsage.java | 0 .../com/amazon/aace/location/Location.java | 0 .../aace/location/LocationProvider.java | 5 + .../java/com/amazon/aace/logger/Logger.java | 7 +- .../logger/config/LoggerConfiguration.java | 0 .../aace/network/NetworkInfoProvider.java | 7 +- .../aace/network/NetworkProperties.java | 41 + .../aace/propertymanager/PropertyManager.java | 7 +- .../storage/config/StorageConfiguration.java | 0 .../aace/vehicle/VehicleProperties.java | 0 .../vehicle/config/VehicleConfiguration.java | 0 .../core/assets/PropertyManager_changed.png | Bin 58607 -> 0 bytes modules/core/assets/PropertyManager_get.png | Bin 14470 -> 0 bytes modules/core/assets/PropertyManager_set.png | Bin 20177 -> 0 bytes .../diagrams/out/AuthProvider_login.png | Bin 0 -> 98823 bytes .../diagrams/out/AuthProvider_logout.png | Bin 0 -> 90982 bytes .../out}/Authorization_cancel.png | Bin .../out}/Authorization_logout.png | Bin .../out}/Authorization_start.png | Bin .../out/authprovider-cancel-sequence.png | Bin 0 -> 18159 bytes .../out/authprovider-logout-sequence.png | Bin 0 -> 26550 bytes .../out/authprovider-start-sequence.png | Bin 0 -> 76603 bytes modules/core/assets/diagrams/out/ducking.png | Bin 0 -> 54173 bytes .../assets/diagrams/out/ducking_3p_event.png | Bin 0 -> 66693 bytes .../diagrams/src/AudioInput_audio.plantuml | 31 + .../diagrams/src/AudioInput_duck.plantuml | 44 + .../diagrams/src/AudioOutput_duck3rd.plantuml | 49 + .../diagrams/src/AudioOutput_reply.plantuml | 34 + .../src}/Authorization_cancel.plantuml | 0 .../src}/Authorization_logout.plantuml | 0 .../src}/Authorization_start.plantuml | 0 .../src/authprovider-cancel-sequence.plantuml | 15 + .../src/authprovider-logout-sequence.plantuml | 19 + .../src/authprovider-start-sequence.plantuml | 33 + modules/core/cmake/FindSQLite3.cmake | 18 - modules/core/cmake/aac-core-module.cmake | 92 + modules/core/conanfile.py | 47 + modules/core/engine/CMakeLists.txt | 263 - .../Engine/Audio/AudioInputChannelInterface.h | 22 +- .../AACE/Engine/Audio/AudioInputEngineImpl.h | 2 +- .../Audio/AudioOutputChannelInterface.h | 3 + .../AACE/Engine/Audio/AudioOutputEngineImpl.h | 4 + .../AACE/Engine/Audio/IStreamAudioStream.h | 55 + .../include/AACE/Engine/Core/EngineImpl.h | 18 +- .../AACE/Engine/Core/ServiceDescription.h | 6 + .../DeviceUsage/DeviceUsageEngineImpl.h | 2 - .../Location/LocationServiceInterface.h | 2 + .../LocationServiceObserverInterface.h | 2 + .../AACE/Engine/MessageBroker}/Message.h | 13 +- .../MessageBrokerEngineService.h | 77 + .../Engine/MessageBroker/MessageBrokerImpl.h | 99 + .../MessageBroker}/MessageBrokerInterface.h | 8 +- .../MessageBrokerServiceInterface.h | 46 + .../MessageHandlerEngineService.h | 79 + .../Engine/MessageBroker}/PublishMessage.h | 14 +- .../Engine/MessageBroker/StreamManagerImpl.h | 58 + .../MessageBroker/StreamManagerInterface.h | 41 + .../Engine/Network/NetworkEngineService.h | 5 + .../AACE/Engine/Network/NetworkInfoObserver.h | 9 + .../Network/NetworkInfoProviderEngineImpl.h | 1 + .../PropertyListenerInterface.h | 2 + .../include/AACE/Engine/Utils/JSON/JSON.h | 2 +- .../AACE/Engine/Utils/String/StringUtils.h | 3 - .../engine/src/Audio/AudioInputEngineImpl.cpp | 17 +- .../src/Audio/AudioOutputEngineImpl.cpp | 43 + .../engine/src/Audio/IStreamAudioStream.cpp | 70 + modules/core/engine/src/EngineImpl.cpp | 55 + .../engine/src/Logger/LoggerEngineService.cpp | 10 +- .../engine/src/Logger/Sinks/SyslogSink.cpp | 18 +- .../engine/src/MessageBroker}/Message.cpp | 8 +- .../MessageBrokerEngineService.cpp | 163 + .../src/MessageBroker/MessageBrokerImpl.cpp | 303 + .../MessageBrokerServiceInterface.cpp | 27 + .../MessageHandlerEngineService.cpp | 162 + .../src/MessageBroker}/PublishMessage.cpp | 19 +- .../src/MessageBroker/StreamManagerImpl.cpp | 82 + .../src/Network/NetworkEngineService.cpp | 28 + .../Network/NetworkInfoProviderEngineImpl.cpp | 25 + .../core/engine/src/ServiceDescription.cpp | 29 +- .../core/engine/src/Utils/Encoding/Base64.cpp | 12 +- modules/core/engine/src/Utils/JSON/JSON.cpp | 7 +- .../engine/src/Utils/String/StringUtils.cpp | 2 +- modules/core/engine/test/CMakeLists.txt | 92 - .../Audio/MockAudioInputChannelInterface.h | 37 - modules/core/engine/test/src/main.cpp | 6 - modules/core/platform/CMakeLists.txt | 75 - .../AACE/Audio/AudioEngineInterfaces.h | 18 + .../platform/include/AACE/Audio/AudioFormat.h | 18 +- .../include/AACE/Audio/AudioInputProvider.h | 8 +- .../platform/include/AACE/Audio/AudioOutput.h | 49 + .../include/AACE/Audio/AudioOutputProvider.h | 8 +- .../AACE/Authorization/Authorization.h | 7 +- .../core/platform/include/AACE/Core/Engine.h | 6 + .../include/AACE/Core/MessageBroker.h | 63 + .../include/AACE/Core/MessageStream.h | 87 + .../DeviceUsage/DeviceUsageEngineInterfaces.h | 2 + .../include/AACE/Location/LocationProvider.h | 5 + .../LocationProviderEngineInterface.h | 2 + .../platform/include/AACE/Logger/Logger.h | 7 +- .../AACE/Logger/LoggerEngineInterfaces.h | 2 + .../include/AACE/Metrics/MetricsUploader.h | 7 +- .../AACE/Network/NetworkEngineInterfaces.h | 2 + .../AACE/Network/NetworkInfoProvider.h | 7 +- .../include/AACE/Network/NetworkProperties.h | 17 +- .../AACE/PropertyManager/PropertyManager.h | 7 +- .../PropertyManagerEngineInterface.h | 2 + .../core/platform/src/Audio/AudioOutput.cpp | 6 + .../Audio/MockAudioInputChannelInterface.h | 39 + .../Unit}/Audio/MockAudioManagerInterface.h | 8 +- .../Audio/MockAudioOutputChannelInterface.h | 11 +- .../MockAuthorizationProviderListener.h | 8 +- .../AACE/Test/Unit}/Core/CoreTestHelper.h | 8 +- .../Test/Unit}/Core/MockEngineConfiguration.h | 8 +- .../Test/Unit}/Core/MockPlatformInterface.h | 8 +- .../MockPropertyManagerServiceInterface.h | 6 +- .../unit/framework}/src/CoreTestHelper.cpp | 8 +- .../tests}/AuthorizationEngineImplTest.cpp | 0 .../unit/tests}/EngineImplTest.cpp | 13 +- .../tests}/LocationProviderEngineImplTest.cpp | 0 .../unit/tests/ServiceDescriptionTest.cpp | 91 + .../tests}/VehicleConfigurationImplTest.cpp | 14 +- modules/custom-domain/README.md | 114 + .../Engine/CustomDomain/AASBCustomDomain.h | 63 + .../AASBCustomDomainEngineService.h | 44 + .../aasb/messages/CustomDomain.yml | 87 + .../aasb/src/AASBCustomDomain.cpp | 187 + .../src/AASBCustomDomainEngineService.cpp | 61 + .../android/src/main/AndroidManifest.xml | 4 + .../assets/meta-aac/aace-custom-domain.json | 5 + .../JNI/CustomDomain/CustomDomainBinder.h | 98 + .../src/CustomDomain/CustomDomainBinder.cpp | 177 + .../aace/customDomain/CustomDomain.java | 205 + .../custom-domain/assets/custom_context.png | Bin 0 -> 66603 bytes .../assets/custom_directives_events.png | Bin 0 -> 111921 bytes modules/custom-domain/conanfile.py | 9 + .../CustomDomainCapabilityAgent.h | 266 + .../CustomDomain/CustomDomainEngineImpl.h | 156 + .../CustomDomain/CustomDomainEngineService.h | 61 + .../CustomDomainHandlerInterface.h | 103 + .../src/CustomDomainCapabilityAgent.cpp | 427 + .../engine/src/CustomDomainEngineImpl.cpp | 260 + .../engine/src/CustomDomainEngineService.cpp | 84 + .../include/AACE/CustomDomain/CustomDomain.h | 184 + .../CustomDomainEngineInterface.h | 66 + .../platform/src/CustomDomain.cpp | 51 + .../tests/CustomDomainCapabilityAgentTest.cpp | 328 + .../unit/tests/CustomDomainEngineImplTest.cpp | 100 + .../loopback-detector/LICENSE | 0 .../loopback-detector/NOTICE | 0 modules/loopback-detector/README.md | 159 + .../android}/src/main/AndroidManifest.xml | 0 .../meta-aac/aace-loopback-detector.json | 5 + .../LoopbackDetectorConfigurationBinder.cpp | 0 .../assets/loopback-detector-data-flow.png | Bin 0 -> 56015 bytes modules/loopback-detector/conanfile.py | 9 + .../loopback-detector/engine/CMakeLists.txt | 0 .../engine/src/LoopbackDetector.cpp | 2 +- .../engine/src/LoopbackDetector.h | 0 .../src/LoopbackDetectorEngineService.cpp | 0 .../src/LoopbackDetectorEngineService.h | 0 modules/messaging/CMakeLists.txt | 53 - modules/messaging/README.md | 298 +- modules/messaging/aac-module-messaging.bb | 7 - .../AASB/Engine/Messaging/AASBMessaging.h | 8 +- .../Messaging/AASBMessagingEngineService.h | 8 +- modules/messaging/aasb/messages/Messaging.yml | 124 + .../messaging/aasb}/src/AASBMessaging.cpp | 6 +- .../aasb}/src/AASBMessagingEngineService.cpp | 8 +- .../android}/src/main/AndroidManifest.xml | 0 .../main/assets/meta-aac/aace-messaging.json | 5 + .../AACE/JNI/Messaging/MessagingBinder.h | 0 .../cpp/src/Messaging/MessagingBinder.cpp | 0 .../com/amazon/aace/messaging/Messaging.java | 7 +- .../aac-messaging-reading-messages.plantuml | 47 + .../assets/aac-messaging-reading-messages.png | Bin 47057 -> 43716 bytes .../aac-messaging-reply-message.plantuml | 65 + .../assets/aac-messaging-reply-message.png | Bin 75027 -> 64698 bytes .../aac-messaging-sending-messages.plantuml | 41 + .../assets/aac-messaging-sending-messages.png | Bin 32098 -> 31238 bytes ...ssaging-endpoint-state-connection.plantuml | 35 + ...te-messaging-endpoint-state-connection.png | Bin 0 -> 19474 bytes ...saging-endpoint-state-permissions.plantuml | 35 + ...e-messaging-endpoint-state-permissions.png | Bin 0 -> 25981 bytes modules/messaging/conanfile.py | 9 + modules/messaging/engine/CMakeLists.txt | 62 - modules/messaging/engine/test/CMakeLists.txt | 27 - modules/messaging/platform/CMakeLists.txt | 39 - .../include/AACE/Messaging/Messaging.h | 7 +- .../AACE/Messaging/MessagingEngineInterface.h | 2 + .../unit/tests}/MessagingEngineImplTest.cpp | 12 +- modules/navigation/.gitignore | 1 - modules/navigation/CMakeLists.txt | 59 - modules/navigation/README.md | 908 +- modules/navigation/aac-module-navigation.bb | 7 - .../AASB/Engine/Navigation/AASBNavigation.h | 8 +- .../Navigation/AASBNavigationEngineService.h | 8 +- .../navigation/aasb/messages/Navigation.yml | 283 + .../navigation/aasb}/src/AASBNavigation.cpp | 7 +- .../aasb}/src/AASBNavigationEngineService.cpp | 8 +- .../android}/src/main/AndroidManifest.xml | 0 .../main/assets/meta-aac/aace-navigation.json | 5 + .../AACE/JNI/Navigation/NavigationBinder.h | 0 .../cpp/src/Navigation/NavigationBinder.cpp | 0 .../NavigationConfigurationBinder.cpp | 0 .../amazon/aace/navigation/Navigation.java | 7 +- .../config/NavigationConfiguration.java | 0 .../navigation/assets/add_waypoint.plantuml | 78 +- modules/navigation/assets/add_waypoint.png | Bin 71871 -> 91249 bytes .../assets/announce_maneuver.plantuml | 57 +- .../navigation/assets/announce_maneuver.png | Bin 42647 -> 54803 bytes .../assets/announce_road_regulation.plantuml | 45 +- .../assets/announce_road_regulation.png | Bin 43703 -> 56540 bytes .../assets/cancel_navigation.plantuml | 40 +- .../navigation/assets/cancel_navigation.png | Bin 50234 -> 37031 bytes .../navigation/assets/map_control.plantuml | 49 +- modules/navigation/assets/map_control.png | Bin 54453 -> 44901 bytes .../navigate_previous_waypoint.plantuml | 45 +- .../assets/navigate_previous_waypoint.png | Bin 44134 -> 55935 bytes .../assets/remove_waypoint.plantuml | 76 +- modules/navigation/assets/remove_waypoint.png | Bin 79743 -> 99214 bytes .../assets/show_alternate_routes.plantuml | 47 +- .../assets/show_alternate_routes.png | Bin 42177 -> 64231 bytes .../assets/show_previous_waypoints.plantuml | 47 +- .../assets/show_previous_waypoints.png | Bin 43373 -> 55237 bytes .../assets/start_navigation.plantuml | 56 +- .../navigation/assets/start_navigation.png | Bin 43782 -> 55261 bytes modules/navigation/conanfile.py | 9 + modules/navigation/engine/CMakeLists.txt | 63 - modules/navigation/engine/test/CMakeLists.txt | 29 - .../engine/test/MockAttachmentManager.h | 51 - modules/navigation/platform/CMakeLists.txt | 36 - .../include/AACE/Navigation/Navigation.h | 7 +- .../Navigation/NavigationEngineInterfaces.h | 2 + ...avigationAssistanceCapabilityAgentTest.cpp | 38 +- .../tests}/NavigationCapabilityAgentTest.cpp | 16 +- .../unit/tests}/NavigationEngineImplTest.cpp | 14 +- modules/phone-control/.gitignore | 1 - modules/phone-control/CMakeLists.txt | 55 - modules/phone-control/README.md | 415 +- .../phone-control/aac-module-phone-control.bb | 7 - .../AASBPhoneCallController.h | 8 +- .../AASBPhoneCallControllerEngineService.h | 8 +- .../aasb/messages/PhoneCallController.yml | 170 + .../aasb}/src/AASBPhoneCallController.cpp | 13 +- .../AASBPhoneCallControllerEngineService.cpp | 8 +- .../android}/src/main/AndroidManifest.xml | 0 .../assets/meta-aac/aace-phonecontrol.json | 5 + .../PhoneControl/PhoneCallControllerBinder.h | 0 .../PhoneCallControllerBinder.cpp | 0 .../phonecontrol/PhoneCallController.java | 546 + .../aac-pcc-connection-state-changed.plantuml | 33 + .../aac-pcc-connection-state-changed.png | Bin 0 -> 20353 bytes ...-pcc-device-configuration-updated.plantuml | 27 + .../aac-pcc-device-configuration-updated.png | Bin 0 -> 15299 bytes .../assets/aac-pcc-inbound-call.plantuml | 74 + .../assets/aac-pcc-inbound-call.png | Bin 93965 -> 83522 bytes .../assets/aac-pcc-outbound-call.plantuml | 54 + .../assets/aac-pcc-outbound-call.png | Bin 79475 -> 51866 bytes modules/phone-control/conanfile.py | 9 + modules/phone-control/engine/CMakeLists.txt | 60 - .../PhoneCallControllerCapabilityAgent.cpp | 256 +- .../phone-control/engine/test/CMakeLists.txt | 27 - .../engine/test/MockAttachmentManager.h | 51 - modules/phone-control/platform/CMakeLists.txt | 39 - .../PhoneCallController/PhoneCallController.h | 7 +- .../PhoneCallControllerEngineInterfaces.h | 2 + ...PhoneCallControllerCapabilityAgentTest.cpp | 48 +- .../PhoneCallControllerEngineImplTest.cpp | 14 +- modules/system-audio/README.md | 218 + .../system-audio/aal}/.gitignore | 0 modules/system-audio/aal/CMakeLists.txt | 118 + .../system-audio}/aal/README.md | 0 modules/system-audio/aal/conanfile.py | 123 + .../system-audio}/aal/include/aal/aal.h | 0 .../system-audio}/aal/include/aal/common.h | 0 .../aal/lib/c-ringbuf/.clang-format | 0 .../aal/lib/c-ringbuf/.github/CONTRIBUTING.md | 0 .../lib/c-ringbuf/.github/ISSUE_TEMPLATE.md | 0 .../.github/PULL_REQUEST_TEMPLATE.md | 0 .../aal/lib/c-ringbuf/.gitignore | 0 .../system-audio}/aal/lib/c-ringbuf/COPYING | 0 .../system-audio}/aal/lib/c-ringbuf/Makefile | 0 .../system-audio}/aal/lib/c-ringbuf/README.md | 0 .../aal/lib/c-ringbuf/ringbuf-test.c | 0 .../system-audio}/aal/lib/c-ringbuf/ringbuf.c | 0 .../system-audio}/aal/lib/c-ringbuf/ringbuf.h | 0 .../system-audio}/aal/src/common.c | 45 +- modules/system-audio/aal/src/gstreamer/core.c | 578 + .../system-audio}/aal/src/gstreamer/core.h | 0 .../aal/src/gstreamer/mathstubs.c | 7 + .../system-audio}/aal/src/gstreamer/player.c | 0 .../aal/src/gstreamer/recorder.c | 0 .../system-audio}/aal/src/omxal/core.c | 0 .../system-audio}/aal/src/omxal/core.h | 0 .../system-audio}/aal/src/omxal/player.c | 0 .../system-audio}/aal/src/omxal/player.h | 0 modules/system-audio/aal/src/qsa/core.c | 390 + .../system-audio}/aal/src/qsa/core.h | 3 +- .../system-audio}/aal/src/qsa/player.c | 8 +- .../system-audio}/aal/src/qsa/recorder.c | 0 .../system-audio}/aal/src/test/CMakeLists.txt | 0 .../system-audio}/aal/src/test/README.md | 0 .../system-audio}/aal/src/test/player.cpp | 0 .../system-audio}/aal/src/test/recorder.cpp | 0 modules/system-audio/conanfile.py | 36 + .../configs/linux/config-system-audio.json | 0 .../configs/neutrino/config-system-audio.json | 0 .../AACE/Engine/SystemAudio/AudioInputImpl.h | 0 .../AACE/Engine/SystemAudio/AudioOutputImpl.h | 6 + .../SystemAudio/SystemAudioEngineService.h | 0 .../AACE/Engine/SystemAudio/Throttle.h | 0 .../engine/src/AudioInputImpl.cpp | 0 .../engine/src/AudioOutputImpl.cpp | 58 +- .../engine/src/SystemAudioEngineService.cpp | 0 .../text-to-speech-provider/CMakeLists.txt | 44 - modules/text-to-speech-provider/README.md | 22 +- .../aac-module-text-to-speech-provider.bb | 8 - .../android}/src/main/AndroidManifest.xml | 0 .../aace-text-to-speech-provider.json | 5 + modules/text-to-speech-provider/conanfile.py | 9 + .../engine/CMakeLists.txt | 54 - modules/text-to-speech/.gitignore | 5 - modules/text-to-speech/CMakeLists.txt | 53 - modules/text-to-speech/README.md | 232 +- .../aac-module-text-to-speech.bb | 8 - .../Engine/TextToSpeech/AASBTextToSpeech.h | 84 + .../AASBTextToSpeechEngineService.h | 8 +- .../aasb/messages/TextToSpeech.yml | 64 + .../aasb}/src/AASBTextToSpeech.cpp | 20 +- .../src/AASBTextToSpeechEngineService.cpp | 8 +- .../android}/src/main/AndroidManifest.xml | 0 .../assets/meta-aac/aace-text-to-speech.json | 5 + .../JNI/TextToSpeech/TextToSpeechBinder.h | 0 .../src/TextToSpeech/TextToSpeechBinder.cpp | 0 .../aace/textToSpeech/TextToSpeech.java | 7 +- .../assets/CapabilitiesReceived.plantuml | 15 - .../assets/CapabilitiesReceived.png | Bin 18816 -> 0 bytes .../assets/GetCapabilities.plantuml | 39 +- .../text-to-speech/assets/GetCapabilities.png | Bin 14933 -> 14640 bytes .../assets/PrepareSpeech.plantuml | 36 +- .../text-to-speech/assets/PrepareSpeech.png | Bin 20971 -> 18932 bytes .../assets/PrepareSpeechCompleted.plantuml | 16 - .../assets/PrepareSpeechCompleted.png | Bin 21378 -> 0 bytes .../assets/PrepareSpeechFailed.plantuml | 16 - .../assets/PrepareSpeechFailed.png | Bin 21106 -> 0 bytes modules/text-to-speech/conanfile.py | 9 + modules/text-to-speech/engine/CMakeLists.txt | 59 - .../Engine/TextToSpeech/PrepareSpeechResult.h | 4 +- .../TextToSpeech/TextToSpeechEngineService.h | 2 +- .../engine/src/TextToSpeechEngineImpl.cpp | 3 + .../engine/src/TextToSpeechEngineService.cpp | 15 +- .../text-to-speech/engine/test/CMakeLists.txt | 27 - .../text-to-speech/platform/CMakeLists.txt | 37 - .../include/AACE/TextToSpeech/TextToSpeech.h | 7 +- .../tests}/TextToSpeechEngineImplTest.cpp | 14 +- platforms/android/.gitignore | 73 - .../alexa-auto-client-service/README.md | 797 - .../android-service/.gitignore | 9 - .../android-service/README.md | 573 - .../android-service/build.gradle | 76 - .../modules/aacs-extra/build.gradle | 32 - .../android-service/service/build.gradle | 141 - .../assets/file-util-res/aacs_config.json | 226 - .../service/src/main/AndroidManifest.xml | 77 - .../ComponentRegistry.java | 170 - .../mediaPlayer/exo/MediaSourceFactory.java | 178 - .../mediaPlayer/exo/PlaylistParser.java | 110 - .../raw/RawAudioOutputHandler.java | 273 - .../mediaManager/LocalMediaSourceHandler.java | 684 - .../PropertyManagerHandler.java | 36 - .../SystemPropertyChangeReceiver.java | 158 - .../alexaautoclientservice/util/FileUtil.java | 840 - .../util/MediaPlayerUtil.java | 54 - .../android-service/settings.gradle | 1 - .../assets/AACS_CBLLogin.png | Bin 40862 -> 0 bytes .../assets/AACS_CBLLogin.puml | 26 - .../assets/config.json | 259 - .../commonutils/aacscommonutils/build.gradle | 45 - .../aacs/common/PlaybackControlMessages.java | 85 - .../commonutils/build.gradle | 46 - .../commonutils/settings.gradle | 7 - .../constants/aacsconstants/build.gradle | 32 - .../constants/build.gradle | 27 - .../alexa-auto-client-service/ipc/.gitignore | 17 - .../alexa-auto-client-service/ipc/README.md | 213 - .../ipc/build.gradle | 26 - .../app-components/alexa-auto-apis/README.md | 35 - .../alexa-auto-apis/build.gradle | 50 - .../alexa-auto-apl-renderer/README.md | 174 - .../alexa-auto-apl-renderer/build.gradle | 84 - .../src/main/AndroidManifest.xml | 36 - .../src/main/assets/APLViewport.json | 113 - .../amazon/alexa/auto/apl/APLActivity.java | 180 - .../com/amazon/alexa/auto/apl/Constants.java | 22 - .../alexa/auto/apl/handler/APLHandler.java | 258 - .../alexa/auto/apl/receiver/APLReceiver.java | 47 - .../src/main/res/layout/activity_apl.xml | 18 - .../src/main/res/layout/apl_view.xml | 12 - .../auto/apl/handler/APLHandlerTest.java | 60 - .../alexa-auto-apps-common-ui/build.gradle | 56 - .../amazon_alexa_placeholder_logo.png | Bin 6152 -> 0 bytes .../alexa-auto-apps-common-util/README.md | 3 - .../alexa-auto-apps-common-util/build.gradle | 62 - .../src/main/AndroidManifest.xml | 5 - .../alexa/auto/apps/common/Constants.java | 35 - .../alexa/auto/apps/common/util/FileUtil.java | 200 - .../alexa-auto-carcontrol/README.md | 191 - .../aacscarcontrol/build.gradle | 60 - .../alexa-auto-carcontrol/build.gradle | 46 - .../alexa-auto-carcontrol/settings.gradle | 9 - .../alexa-auto-comms-ui/README.md | 18 - .../alexa-auto-comms-ui/build.gradle | 81 - .../src/main/AndroidManifest.xml | 25 - .../amazon/alexa/auto/comms/ui/Constants.java | 29 - .../auto/comms/ui/ContactsControllerImpl.java | 170 - .../ui/db/ConnectedBTDeviceRepository.java | 141 - .../ui/dependencies/CommunicationModule.java | 24 - .../comms/ui/receiver/BluetoothReceiver.java | 56 - .../communication_setup_fragment.xml | 88 - .../layout/communication_setup_fragment.xml | 89 - .../src/main/res/values-land/dimens.xml | 24 - .../src/main/res/values/dimens.xml | 27 - .../src/main/res/values/strings.xml | 21 - .../alexa-auto-contacts/README.md | 129 - .../aacscontacts/build.gradle | 50 - .../alexa-auto-contacts/build.gradle | 45 - .../alexa-auto-contacts/settings.gradle | 9 - .../alexa-auto-device-usage/README.md | 40 - .../alexa-auto-lwa-auth/build.gradle | 62 - .../src/main/AndroidManifest.xml | 57 - .../amazon/alexa/auto/lwa/AuthReceiver.java | 110 - .../amazon/alexa/auto/lwa/CBLReceiver.java | 216 - .../alexa/auto/lwa/LWAAuthController.java | 433 - .../alexa-auto-media-player/README.md | 30 - .../alexa-auto-media-player/build.gradle | 89 - .../src/main/AndroidManifest.xml | 71 - .../aacs/handlers/AudioPlayerHandler.java | 319 - .../auto/media/player/MediaSourceFactory.java | 131 - .../media/session/MediaSessionManager.java | 515 - .../media/session/PlaybackController.java | 107 - .../alexa-auto-navigation/build.gradle | 74 - .../src/main/res/values/dimens.xml | 60 - .../alexa-auto-settings/README.md | 15 - .../alexa-auto-settings/build.gradle | 88 - .../src/main/AndroidManifest.xml | 27 - .../src/main/assets/locales.json | 109 - .../AlexaSettingsLanguagesFragment.java | 203 - .../auto/settings/config/PreferenceKeys.java | 53 - .../layout/settings_alexa_language_layout.xml | 774 - .../src/main/res/values/strings.xml | 64 - .../app-components/alexa-auto-setup/README.md | 29 - .../alexa-auto-setup/build.gradle | 79 - .../setup/dependencies/SetupComponent.java | 61 - .../receiver/NetworkStateChangeReceiver.java | 36 - .../fragment/EnablePreviewModeFragment.java | 132 - .../auth_provider_login_finished.xml | 128 - .../main/res/layout-land/cbl_login_error.xml | 66 - .../res/layout-land/cbl_login_finished.xml | 101 - .../res/layout-land/enable_preview_mode.xml | 91 - .../main/res/layout-land/location_consent.xml | 97 - .../layout-land/login_display_cbl_code.xml | 80 - .../src/main/res/layout-land/login_start.xml | 75 - .../main/res/layout-land/network_fragment.xml | 82 - .../res/layout-land/setup_not_complete.xml | 67 - .../layout-land/start_language_selection.xml | 55 - .../layout/auth_provider_login_finished.xml | 131 - .../src/main/res/layout/cbl_login_error.xml | 67 - .../main/res/layout/cbl_login_finished.xml | 104 - .../main/res/layout/enable_preview_mode.xml | 93 - .../src/main/res/layout/location_consent.xml | 97 - .../res/layout/login_display_cbl_code.xml | 82 - .../src/main/res/layout/login_start.xml | 75 - .../src/main/res/layout/network_fragment.xml | 82 - .../main/res/layout/setup_not_complete.xml | 67 - .../res/layout/start_language_selection.xml | 54 - .../src/main/res/values-land/dimens.xml | 28 - .../src/main/res/values/dimens.xml | 34 - .../src/main/res/values/strings.xml | 50 - .../alexa-auto-telephony/README.md | 231 - .../aacstelephony/build.gradle | 52 - .../aacstelephony/consumer-rules.pro | 0 .../aacstelephony/PhoneCallController.java | 357 - .../alexa-auto-telephony/build.gradle | 46 - .../alexa-auto-telephony/settings.gradle | 9 - .../build.gradle | 77 - .../src/main/res/layout/weather.xml | 105 - .../src/main/res/values/dimens.xml | 57 - .../app-components/alexa-auto-tts/README.md | 177 - .../alexa-auto-tts/aacstts/build.gradle | 52 - .../alexa-auto-tts/build.gradle | 27 - .../alexa-auto-tts/gradle.properties | 20 - .../alexa-auto-voice-interaction/README.md | 11 - .../alexa-auto-voice-interaction/build.gradle | 74 - .../earcon/EarconController.java | 116 - .../receiver/AACSBroadcastReceiver.java | 88 - .../service/AutoVoiceInteractionSession.java | 362 - .../src/main/res/values/styles.xml | 15 - .../receiver/AACSBroadcastReceiverTest.java | 155 - .../AutoVoiceInteractionSessionTest.java | 129 - platforms/android/modules/abifilter.gradle | 88 - .../modules/addressbook/CMakeLists.txt | 55 - .../android/modules/addressbook/README.md | 203 - .../assets/remove_contacts.plantuml | 35 - .../addressbook/assets/remove_contacts.png | Bin 22159 -> 0 bytes .../assets/remove_navigation_fav.plantuml | 36 - .../assets/remove_navigation_fav.png | Bin 22381 -> 0 bytes .../assets/upload_contacts.plantuml | 54 - .../addressbook/assets/upload_contacts.png | Bin 44530 -> 0 bytes .../assets/upload_navigation_fav.plantuml | 54 - .../assets/upload_navigation_fav.png | Bin 46483 -> 0 bytes .../android/modules/addressbook/build.gradle | 67 - .../assets/meta-aac/aace-addressbook.json | 5 - .../android/modules/alexa/CMakeLists.txt | 161 - platforms/android/modules/alexa/README.md | 1382 - platforms/android/modules/alexa/build.gradle | 67 - .../src/main/assets/meta-aac/aace-alexa.json | 5 - .../amazon/aace/alexa/PlaybackController.java | 173 - .../android/modules/apl-render/README.md | 247 - .../android/modules/apl-render/build.gradle | 74 - .../apl/android/render/APLPresenter.java | 623 - .../apl-render/src/main/libs/.gitignore | 2 - platforms/android/modules/apl/CMakeLists.txt | 59 - platforms/android/modules/apl/README.md | 227 - platforms/android/modules/apl/build.gradle | 68 - .../src/main/assets/meta-aac/aace-apl.json | 5 - .../modules/car-control/CMakeLists.txt | 54 - .../android/modules/car-control/README.md | 2172 -- .../assets/meta-aac/aace-car-control.json | 5 - .../android/modules/car-control/build.gradle | 66 - .../assets/meta-aac/aace-car-control.json | 5 - platforms/android/modules/cbl/CMakeLists.txt | 54 - platforms/android/modules/cbl/README.md | 392 - platforms/android/modules/cbl/build.gradle | 67 - .../src/main/assets/meta-aac/aace-cbl.json | 5 - .../modules/connectivity/CMakeLists.txt | 62 - .../android/modules/connectivity/README.md | 128 - .../Connectivity-Sequence-CloudAskReport.png | Bin 43591 -> 0 bytes .../Connectivity-Sequence-CloudAskReport.puml | 33 - .../Connectivity-Sequence-ConnectCloud.png | Bin 46817 -> 0 bytes .../Connectivity-Sequence-ConnectCloud.puml | 36 - .../Connectivity-Sequence-DeviceDiscovery.png | Bin 32293 -> 0 bytes ...Connectivity-Sequence-DeviceDiscovery.puml | 24 - ...ctivity-Sequence-sendConnectivityEvent.png | Bin 72209 -> 0 bytes ...tivity-Sequence-sendConnectivityEvent.puml | 31 - .../android/modules/connectivity/build.gradle | 68 - .../assets/meta-aac/aace-connectivity.json | 5 - platforms/android/modules/core/CMakeLists.txt | 72 - platforms/android/modules/core/README.md | 721 - .../core/assets/Authorization_cancel.plantuml | 13 - .../core/assets/Authorization_cancel.png | Bin 17976 -> 0 bytes .../core/assets/Authorization_logout.plantuml | 15 - .../core/assets/Authorization_logout.png | Bin 22489 -> 0 bytes .../core/assets/Authorization_start.plantuml | 38 - .../core/assets/Authorization_start.png | Bin 63325 -> 0 bytes .../core/assets/PropertyManager_changed.png | Bin 58607 -> 0 bytes .../core/assets/PropertyManager_get.png | Bin 14470 -> 0 bytes .../core/assets/PropertyManager_set.png | Bin 20177 -> 0 bytes platforms/android/modules/core/build.gradle | 64 - .../src/main/assets/meta-aac/aace-core.json | 5 - .../aace/network/NetworkProperties.java | 27 - platforms/android/modules/gradle.properties | 17 - .../android/modules/maccandroid/.classpath | 6 - .../android/modules/maccandroid/build.gradle | 55 - .../android/modules/messaging/CMakeLists.txt | 53 - platforms/android/modules/messaging/README.md | 114 - .../assets/aac-messaging-reading-messages.png | Bin 47057 -> 0 bytes .../assets/aac-messaging-reply-message.png | Bin 75027 -> 0 bytes .../assets/aac-messaging-sending-messages.png | Bin 32098 -> 0 bytes .../android/modules/messaging/build.gradle | 67 - .../main/assets/meta-aac/aace-messaging.json | 5 - .../android/modules/navigation/CMakeLists.txt | 54 - .../android/modules/navigation/README.md | 586 - .../navigation/assets/add_waypoint.png | Bin 71871 -> 0 bytes .../navigation/assets/announce_maneuver.png | Bin 42647 -> 0 bytes .../assets/announce_road_regulation.png | Bin 43703 -> 0 bytes .../navigation/assets/cancel_navigation.png | Bin 50234 -> 0 bytes .../modules/navigation/assets/map_control.png | Bin 54453 -> 0 bytes .../assets/navigate_previous_waypoint.png | Bin 44134 -> 0 bytes .../navigation/assets/remove_waypoint.png | Bin 79743 -> 0 bytes .../assets/show_alternate_routes.png | Bin 42177 -> 0 bytes .../assets/show_previous_waypoint.png | Bin 43373 -> 0 bytes .../navigation/assets/start_navigation.png | Bin 43782 -> 0 bytes .../android/modules/navigation/build.gradle | 67 - .../main/assets/meta-aac/aace-navigation.json | 5 - .../modules/phonecontrol/CMakeLists.txt | 53 - .../android/modules/phonecontrol/README.md | 152 - .../android/modules/phonecontrol/build.gradle | 67 - .../assets/meta-aac/aace-phonecontrol.json | 5 - .../phonecontrol/PhoneCallController.java | 541 - platforms/android/modules/settings.gradle | 20 - .../modules/text-to-speech-provider/README.md | 102 - .../text-to-speech-provider/build.gradle | 79 - .../aace-text-to-speech-provider.json | 5 - .../modules/text-to-speech/CMakeLists.txt | 60 - .../android/modules/text-to-speech/README.md | 124 - .../assets/CapabilitiesReceived.plantuml | 15 - .../assets/CapabilitiesReceived.png | Bin 18816 -> 0 bytes .../assets/GetCapabilities.plantuml | 14 - .../text-to-speech/assets/GetCapabilities.png | Bin 14933 -> 0 bytes .../assets/PrepareSpeech.plantuml | 19 - .../text-to-speech/assets/PrepareSpeech.png | Bin 20971 -> 0 bytes .../assets/PrepareSpeechCompleted.plantuml | 16 - .../assets/PrepareSpeechCompleted.png | Bin 21378 -> 0 bytes .../assets/PrepareSpeechFailed.plantuml | 16 - .../assets/PrepareSpeechFailed.png | Bin 21106 -> 0 bytes .../modules/text-to-speech/build.gradle | 66 - .../assets/meta-aac/aace-text-to-speech.json | 5 - .../alexa-auto-app/README.md | 415 - .../alexa-auto-app/build.gradle | 119 - .../alexa-auto-app/gradle.properties | 15 - .../src/main/AndroidManifest.xml | 44 - .../src/main/assets/config/aacs_config.json | 80 - samples/android-aacs-sample-app/build.gradle | 104 - .../android-aacs-sample-app/settings.gradle | 77 - samples/android/.gitignore | 63 - samples/android/README.md | 295 - samples/android/app/.gitignore | 1 - samples/android/app/build.gradle | 90 - .../sampleapp/ExampleInstrumentedTest.java | 41 - .../android/app/src/main/AndroidManifest.xml | 56 - .../aidl/com/amazon/alexalve/ILVCClient.aidl | 205 - .../aidl/com/amazon/alexalve/ILVCService.aidl | 64 - .../app/src/main/assets/CarControlAssets.json | 141 - .../android/app/src/main/assets/Contacts.json | 228 - .../src/main/assets/ConversationsReport.json | 40 - .../src/main/assets/NavigationFavorites.json | 320 - .../app/src/main/assets/NavigationState.json | 62 - .../app/src/main/assets/app_config.json | 9 - .../app/src/main/assets/models/.gitkeep | 0 .../java/com/amazon/sampleapp/FileUtils.java | 203 - .../sampleapp/LVCInteractionService.java | 328 - .../sampleapp/LimitedSizeArrayList.java | 43 - .../com/amazon/sampleapp/MainActivity.java | 1514 -- .../sampleapp/NetworkStatsManagerRunner.java | 226 - .../amazon/sampleapp/SampleApplication.java | 60 - .../impl/AddressBook/AddressBookHandler.java | 298 - .../sampleapp/impl/Alerts/AlertsHandler.java | 82 - .../impl/AlexaClient/AlexaClientHandler.java | 144 - .../AlexaSpeaker/AlexaSpeakerHandler.java | 241 - .../impl/Audio/AudioFocusController.java | 316 - .../impl/Audio/AudioInputHandler.java | 206 - .../impl/Audio/AudioInputProviderHandler.java | 53 - .../impl/Audio/AudioOutputHandler.java | 423 - .../Audio/AudioOutputProviderHandler.java | 64 - .../impl/Audio/MediaSourceFactory.java | 192 - .../sampleapp/impl/Audio/PlaylistParser.java | 107 - .../impl/Audio/RawAudioOutputHandler.java | 270 - .../sampleapp/impl/Audio/Releasable.java | 8 - .../impl/Audio/UnifiedAudioOutput.java | 209 - .../impl/AudioPlayer/AudioPlayerHandler.java | 36 - .../Authorization/AuthorizationHandler.java | 123 - .../CBLAuthorizationHandler.java | 243 - .../impl/CarControl/BoolController.java | 35 - .../CarControl/CarControlDataProvider.java | 712 - .../impl/CarControl/CarControlHandler.java | 312 - .../impl/CarControl/ModeController.java | 50 - .../impl/CarControl/RangeController.java | 45 - .../impl/DeviceSetup/DeviceSetupHandler.java | 59 - .../impl/DeviceUsage/DeviceUsageHandler.java | 236 - .../DoNotDisturb/DoNotDisturbHandler.java | 109 - .../impl/EqualizerController/EQUtils.java | 69 - .../EqualizerConfiguration.java | 93 - .../EqualizerControllerHandler.java | 319 - .../impl/ExternalMediaPlayer/MACCPlayer.java | 399 - .../LocalMediaSource/AMLocalMediaSource.java | 31 - .../BluetoothLocalMediaSource.java | 33 - .../LocalMediaSource/CDLocalMediaSource.java | 31 - .../LocalMediaSource/DABLocalMediaSource.java | 31 - .../LocalMediaSource/DefaultMediaSource.java | 35 - .../LocalMediaSource/FMLocalMediaSource.java | 31 - .../LineInLocalMediaSource.java | 33 - .../LocalMediaSourceHandler.java | 135 - .../SatelliteLocalMediaSource.java | 27 - .../SiriusXMLocalMediaSource.java | 31 - .../LocalMediaSource/USBLocalMediaSource.java | 33 - .../LocationProviderHandler.java | 399 - .../sampleapp/impl/Logger/LoggerFragment.java | 136 - .../sampleapp/impl/Logger/LoggerHandler.java | 226 - .../impl/Messaging/MessagingHandler.java | 726 - .../impl/Navigation/NavigationHandler.java | 480 - .../NetworkConnectionObserver.java | 9 - .../NetworkInfoProviderHandler.java | 282 - .../Notifications/NotificationsHandler.java | 48 - .../PhoneCallControllerHandler.java | 549 - .../PlaybackControllerHandler.java | 494 - .../PropertyManagerHandler.java | 91 - .../SpeechRecognizerHandler.java | 163 - .../SpeechSynthesizerHandler.java | 20 - .../TemplateRuntimeHandler.java | 228 - .../TextToSpeech/TextToSpeechHandler.java | 186 - .../logView/ConfigureViewHolder.java | 872 - .../sampleapp/logView/DownloadImageTask.java | 62 - .../amazon/sampleapp/logView/LogEntry.java | 35 - .../logView/LogRecyclerViewAdapter.java | 410 - .../logView/ViewHolderBodyTemplate1.java | 46 - .../logView/ViewHolderBodyTemplate2.java | 52 - .../sampleapp/logView/ViewHolderCBLCard.java | 56 - .../logView/ViewHolderCBLExpiredCard.java | 36 - .../logView/ViewHolderListTemplate1.java | 66 - .../ViewHolderLocalSearchDetailTemplate1.java | 150 - .../ViewHolderLocalSearchListTemplate1.java | 49 - .../ViewHolderLocalSearchListTemplate2.java | 76 - .../ViewHolderPreviousWaypointsTemplate.java | 51 - .../logView/ViewHolderRenderPlayerInfo.java | 67 - .../ViewHolderStartNavigationTemplate.java | 130 - .../sampleapp/logView/ViewHolderTextLog.java | 41 - .../ViewHolderTrafficDetailsTemplate.java | 72 - .../logView/ViewHolderWeatherTemplate.java | 71 - samples/android/app/src/main/libs/.gitignore | 2 - .../main/res/drawable-hdpi/ic_action_stop.png | Bin 94 -> 0 bytes .../drawable-hdpi/ic_action_tap_to_talk.png | Bin 552 -> 0 bytes .../main/res/drawable-mdpi/ic_action_stop.png | Bin 90 -> 0 bytes .../drawable-mdpi/ic_action_tap_to_talk.png | Bin 369 -> 0 bytes .../drawable-v24/ic_launcher_foreground.xml | 34 - .../res/drawable-xhdpi/ic_action_stop.png | Bin 95 -> 0 bytes .../drawable-xhdpi/ic_action_tap_to_talk.png | Bin 690 -> 0 bytes .../res/drawable-xxhdpi/ic_action_stop.png | Bin 108 -> 0 bytes .../drawable-xxhdpi/ic_action_tap_to_talk.png | Bin 1124 -> 0 bytes .../main/res/drawable/btn_drawer_default.xml | 11 - .../main/res/drawable/btn_drawer_pressed.xml | 8 - .../main/res/drawable/btn_drawer_selector.xml | 7 - .../res/drawable/control_selector_next.xml | 12 - .../res/drawable/control_selector_pause.xml | 12 - .../res/drawable/control_selector_play.xml | 12 - .../res/drawable/control_selector_prev.xml | 12 - .../control_selector_skip_backward.xml | 12 - .../control_selector_skip_forward.xml | 12 - .../drawable/control_toggle_play_pause.xml | 21 - .../src/main/res/drawable/ic_chevron_left.png | Bin 130 -> 0 bytes .../main/res/drawable/ic_chevron_right.png | Bin 128 -> 0 bytes .../ic_control_30sec_back_default.png | Bin 2620 -> 0 bytes .../ic_control_30sec_back_disabled.png | Bin 3693 -> 0 bytes .../ic_control_30sec_back_enabled.png | Bin 3513 -> 0 bytes .../ic_control_30sec_forward_default.png | Bin 2641 -> 0 bytes .../ic_control_30sec_forward_disabled.png | Bin 3337 -> 0 bytes .../ic_control_30sec_forward_enabled.png | Bin 3500 -> 0 bytes .../res/drawable/ic_control_loop_default.png | Bin 2080 -> 0 bytes .../res/drawable/ic_control_loop_disabled.png | Bin 2533 -> 0 bytes .../main/res/drawable/ic_control_loop_on.png | Bin 2582 -> 0 bytes .../res/drawable/ic_control_next_default.png | Bin 1824 -> 0 bytes .../res/drawable/ic_control_next_disabled.png | Bin 1869 -> 0 bytes .../res/drawable/ic_control_next_focus.png | Bin 1528 -> 0 bytes .../res/drawable/ic_control_pause_default.png | Bin 1487 -> 0 bytes .../drawable/ic_control_pause_disabled.png | Bin 1961 -> 0 bytes .../res/drawable/ic_control_pause_focus.png | Bin 1256 -> 0 bytes .../res/drawable/ic_control_play_default.png | Bin 1647 -> 0 bytes .../res/drawable/ic_control_play_disabled.png | Bin 2241 -> 0 bytes .../res/drawable/ic_control_play_focus.png | Bin 1375 -> 0 bytes .../res/drawable/ic_control_prev_default.png | Bin 1828 -> 0 bytes .../res/drawable/ic_control_prev_disabled.png | Bin 1883 -> 0 bytes .../res/drawable/ic_control_prev_focus.png | Bin 1828 -> 0 bytes .../drawable/ic_control_repeat_default.png | Bin 346 -> 0 bytes .../drawable/ic_control_repeat_disabled.png | Bin 346 -> 0 bytes .../res/drawable/ic_control_repeat_on.png | Bin 346 -> 0 bytes .../drawable/ic_control_shuffle_default.png | Bin 2083 -> 0 bytes .../drawable/ic_control_shuffle_disabled.png | Bin 2580 -> 0 bytes .../res/drawable/ic_control_shuffle_on.png | Bin 2697 -> 0 bytes .../ic_control_thumb_down_default.png | Bin 2188 -> 0 bytes .../ic_control_thumb_down_disabled.png | Bin 2638 -> 0 bytes .../res/drawable/ic_control_thumb_down_on.png | Bin 2707 -> 0 bytes .../drawable/ic_control_thumb_up_default.png | Bin 2194 -> 0 bytes .../drawable/ic_control_thumb_up_disabled.png | Bin 2664 -> 0 bytes .../res/drawable/ic_control_thumb_up_on.png | Bin 2718 -> 0 bytes .../src/main/res/drawable/ic_down_arrow.png | Bin 212 -> 0 bytes .../res/drawable/ic_launcher_background.xml | 170 - .../app/src/main/res/drawable/ic_menu.xml | 9 - .../src/main/res/drawable/ic_toggle_loop.xml | 9 - .../main/res/drawable/ic_toggle_repeat.xml | 9 - .../main/res/drawable/ic_toggle_shuffle.xml | 9 - .../res/drawable/ic_toggle_thumb_down.xml | 9 - .../main/res/drawable/ic_toggle_thumb_up.xml | 9 - .../app/src/main/res/drawable/ic_undo.png | Bin 202 -> 0 bytes .../app/src/main/res/drawable/ic_up_arrow.png | Bin 221 -> 0 bytes .../linear_layout_horizontal_divider.xml | 7 - .../app/src/main/res/layout/activity_main.xml | 50 - .../main/res/layout/card_body_template1.xml | 84 - .../main/res/layout/card_body_template2.xml | 111 - .../main/res/layout/card_list_template1.xml | 105 - .../card_list_template1_item_content.xml | 20 - .../layout/card_list_template1_item_index.xml | 20 - .../card_local_search_detail_template1.xml | 300 - .../card_local_search_list_template1.xml | 49 - .../card_local_search_list_template1_item.xml | 63 - .../card_local_search_list_template2.xml | 58 - .../card_local_search_list_template2_item.xml | 167 - .../app/src/main/res/layout/card_lwa_cbl.xml | 58 - .../main/res/layout/card_lwa_cbl_expired.xml | 40 - .../card_previous_waypoints_template.xml | 180 - .../res/layout/card_render_player_info.xml | 191 - .../layout/card_start_navigation_template.xml | 101 - .../layout/card_traffic_details_template.xml | 142 - .../main/res/layout/card_weather_template.xml | 244 - ...card_weather_template_weather_forecast.xml | 74 - .../app/src/main/res/layout/drawer_switch.xml | 33 - .../app/src/main/res/layout/drawer_view.xml | 1873 -- .../src/main/res/layout/eq_band_control.xml | 54 - .../app/src/main/res/layout/eq_section.xml | 117 - .../main/res/layout/log_card_container.xml | 16 - .../app/src/main/res/layout/log_item.xml | 18 - .../app/src/main/res/layout/log_view.xml | 12 - .../src/main/res/layout/menu_item_talk.xml | 8 - .../main/res/layout/playback_controller.xml | 195 - .../app/src/main/res/menu/menu_main.xml | 20 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 - .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 - .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3056 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5024 -> 0 bytes .../src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2096 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2858 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4569 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7098 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6464 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 10676 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9250 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 15523 -> 0 bytes .../res/raw/med_state_bluetooth_connected.mp3 | Bin 43945 -> 0 bytes .../raw/med_state_bluetooth_disconnected.mp3 | Bin 40873 -> 0 bytes .../src/main/res/raw/med_ui_endpointing.wav | Bin 134444 -> 0 bytes .../main/res/raw/med_ui_endpointing_touch.wav | Bin 134444 -> 0 bytes .../app/src/main/res/raw/med_ui_wakesound.wav | Bin 124304 -> 0 bytes .../main/res/raw/med_ui_wakesound_touch.wav | Bin 90656 -> 0 bytes .../app/src/main/res/values/colors.xml | 34 - .../app/src/main/res/values/strings.xml | 213 - .../app/src/main/res/values/styles.xml | 23 - .../main/res/xml/network_security_config.xml | 5 - .../com/amazon/sampleapp/ExampleUnitTest.java | 32 - .../android/assets/android_api_key_fields.png | Bin 49395 -> 0 bytes .../assets/android_sample_add_lwa_lib.png | Bin 276133 -> 0 bytes samples/android/assets/capabilities.png | Bin 190252 -> 0 bytes samples/android/assets/finished_dialog.png | Bin 28164 -> 0 bytes samples/android/build.gradle | 26 - samples/android/gradle.properties | 19 - samples/android/gradlew.bat | 84 - samples/android/modules/sample-apl/.gitignore | 1 - .../android/modules/sample-apl/build.gradle | 66 - .../modules/sample-apl/gradle.properties | 3 - .../modules/sample-apl/proguard-rules.pro | 21 - .../modules/sample-apl/settings.gradle | 1 - .../sample-apl/src/main/AndroidManifest.xml | 2 - .../src/main/assets/config/APLViewport.json | 116 - .../main/assets/sample-app/sample-apl.json | 5 - .../com/amazon/sampleapp/apl/APLFragment.java | 54 - .../com/amazon/sampleapp/apl/APLHandler.java | 181 - .../sampleapp/apl/APLModuleFactory.java | 160 - .../sample-apl/src/main/libs/.gitignore | 2 - .../src/main/res/drawable/customborder.xml | 6 - .../src/main/res/layout/apl_view.xml | 20 - .../modules/sample-connectivity/.gitignore | 1 - .../modules/sample-connectivity/build.gradle | 53 - .../sample-connectivity/gradle.properties | 2 - .../sample-connectivity/settings.gradle | 1 - .../src/main/AndroidManifest.xml | 2 - .../sample-app/sample-connectivity.json | 5 - .../AlexaConnectivityHandler.java | 521 - .../ConnectivityModuleFactory.java | 59 - .../src/main/libs/.gitignore | 2 - .../src/main/res/layout/connectivity_view.xml | 31 - .../src/main/res/values/colors.xml | 7 - .../src/main/res/values/strings.xml | 7 - .../android/modules/sample-core/.gitignore | 1 - .../android/modules/sample-core/build.gradle | 31 - .../modules/sample-core/proguard-rules.pro | 21 - .../sample-core/src/main/AndroidManifest.xml | 2 - .../sampleapp/core/AuthStateObserver.java | 28 - .../AuthorizationHandlerFactoryInterface.java | 35 - .../core/AuthorizationHandlerInterface.java | 56 - ...AuthorizationHandlerObserverInterface.java | 78 - .../sampleapp/core/EngineStatusListener.java | 21 - .../core/LoggerControllerInterface.java | 6 - .../core/ModuleFactoryInterface.java | 18 - .../sampleapp/core/PropertyListener.java | 29 - .../sampleapp/core/SampleAppContext.java | 60 - .../src/main/res/values/strings.xml | 3 - samples/android/settings.gradle | 2 - samples/cpp/.gitignore | 11 - samples/cpp/CMakeLists.txt | 52 +- samples/cpp/README.md | 236 +- samples/cpp/SampleApp/CMakeLists.txt | 447 - .../AddressBook/AddressBookHandler.h | 109 - .../include/SampleApp/Alexa/AlertsHandler.h | 67 - .../SampleApp/Alexa/AlexaClientHandler.h | 69 - .../SampleApp/Alexa/AlexaSpeakerHandler.h | 66 - .../SampleApp/Alexa/AudioPlayerHandler.h | 63 - .../SampleApp/Alexa/DeviceSetupHandler.h | 64 - .../SampleApp/Alexa/DoNotDisturbHandler.h | 64 - .../Alexa/EqualizerControllerHandler.h | 64 - .../SampleApp/Alexa/GlobalPresetHandler.h | 63 - .../SampleApp/Alexa/LocalMediaSourceHandler.h | 91 - .../SampleApp/Alexa/NotificationsHandler.h | 65 - .../Alexa/PlaybackControllerHandler.h | 59 - .../SampleApp/Alexa/SpeechRecognizerHandler.h | 84 - .../SampleApp/Alexa/TemplateRuntimeHandler.h | 76 - .../Audio/AudioInputProviderHandler.h | 127 - .../Audio/AudioOutputProviderHandler.h | 133 - .../Authorization/AuthorizationHandler.h | 131 - .../SampleApp/CarControl/CarControlHandler.h | 100 - .../Communication/CommunicationHandler.h | 100 - .../Connectivity/AlexaConnectivityHandler.h | 68 - .../LocalSearchProviderHandler.h | 101 - .../Location/LocationProviderHandler.h | 63 - .../include/SampleApp/Logger/LoggerHandler.h | 101 - .../SampleApp/Messaging/MessagingHandler.h | 138 - .../SampleApp/Navigation/NavigationHandler.h | 97 - .../Network/NetworkInfoProviderHandler.h | 70 - .../PhoneControl/PhoneControlHandler.h | 98 - .../PropertyManager/PropertyManagerHandler.h | 59 - .../TextToSpeech/TextToSpeechHandler.h | 77 - samples/cpp/SampleApp/include/gsl/contracts.h | 162 - .../SampleApp/include/nlohmann/.clang-format | 2 - .../cpp/SampleApp/include/nlohmann/json.hpp | 20842 ---------------- .../src/AddressBook/AddressBookHandler.cpp | 286 - .../cpp/SampleApp/src/Alexa/AlertsHandler.cpp | 157 - .../src/Alexa/AlexaClientHandler.cpp | 174 - .../src/Alexa/AlexaSpeakerHandler.cpp | 166 - .../src/Alexa/AudioPlayerHandler.cpp | 104 - .../src/Alexa/DeviceSetupHandler.cpp | 83 - .../src/Alexa/DoNotDisturbHandler.cpp | 129 - .../src/Alexa/EqualizerControllerHandler.cpp | 118 - .../src/Alexa/GlobalPresetHandler.cpp | 85 - .../src/Alexa/LocalMediaSourceHandler.cpp | 320 - .../src/Alexa/NotificationsHandler.cpp | 107 - .../src/Alexa/SpeechRecognizerHandler.cpp | 164 - .../src/Alexa/TemplateRuntimeHandler.cpp | 202 - .../src/Audio/AudioInputProviderHandler.cpp | 195 - .../src/Audio/AudioOutputProviderHandler.cpp | 289 - .../Authorization/AuthorizationHandler.cpp | 352 - .../src/CarControl/CarControlHandler.cpp | 334 - .../Communication/CommunicationHandler.cpp | 217 - .../Connectivity/AlexaConnectivityHandler.cpp | 283 - .../LocalSearchProviderHandler.cpp | 144 - .../src/Location/LocationProviderHandler.cpp | 123 - .../SampleApp/src/Logger/LoggerHandler.cpp | 124 - .../src/Navigation/NavigationHandler.cpp | 557 - .../Network/NetworkInfoProviderHandler.cpp | 113 - .../src/PhoneControl/PhoneControlHandler.cpp | 534 - .../PropertyManagerHandler.cpp | 72 - .../src/TextToSpeech/TextToSpeechHandler.cpp | 180 - samples/cpp/SampleApp/src/main.cpp | 270 - samples/cpp/aac-sample-cpp.bb | 27 - samples/cpp/assets/certs/09789157.0 | 24 - samples/cpp/assets/certs/3513523f.0 | 22 - samples/cpp/assets/certs/6d41d539.0 | 31 - samples/cpp/assets/certs/85cf5865.0 | 27 - samples/cpp/assets/certs/8cb5ee0f.0 | 12 - samples/cpp/assets/certs/b204d74a.0 | 28 - samples/cpp/assets/certs/ce5e74ef.0 | 20 - samples/cpp/assets/certs/de6d66f3.0 | 13 - samples/cpp/assets/certs/f387163d.0 | 24 - samples/cpp/assets/config.json.in | 59 - samples/cpp/assets/config/config.json | 91 + samples/cpp/assets/{ => menu}/MENU.md | 21 - samples/cpp/assets/{ => menu}/menu.json | 19 +- samples/cpp/assets/sampledata/Contacts.json | 72 - .../sampledata/NavigationFavorites.json | 96 - samples/cpp/cmake/FindSQLite3.cmake | 18 - samples/cpp/cmake/aac-sampleapp.cmake | 112 + samples/cpp/conanfile.py | 135 + .../include/SampleApp/Activity.h | 0 .../AddressBook/AddressBookHandler.h | 170 + .../include/SampleApp/Alexa/AlertsHandler.h | 141 + .../SampleApp/Alexa/AlexaClientHandler.h | 137 + .../SampleApp/Alexa/AlexaSpeakerHandler.h | 126 + .../SampleApp/Alexa/AudioPlayerHandler.h | 142 + .../SampleApp/Alexa/DeviceSetupHandler.h | 93 + .../SampleApp/Alexa/DoNotDisturbHandler.h | 91 + .../Alexa/EqualizerControllerHandler.h | 133 + .../SampleApp/Alexa/LocalMediaSourceHandler.h | 242 + .../Alexa/MediaPlaybackRequestorHandler.h | 84 + .../SampleApp/Alexa/NotificationsHandler.h | 92 + .../Alexa/PlaybackControllerHandler.h | 88 + .../SampleApp/Alexa/SpeechRecognizerHandler.h | 139 + .../Alexa/SpeechSynthesizerHandler.h | 6 +- .../SampleApp/Alexa/TemplateRuntimeHandler.h | 143 + .../include/SampleApp/Application.h | 95 +- .../include/SampleApp/ApplicationContext.h | 0 .../{SampleApp => }/include/SampleApp/Args.h | 0 .../Audio/AudioInputProviderHandler.h | 100 + .../Audio/AudioOutputProviderHandler.h | 321 + .../AuthProviderAuthorizationHandler.h | 0 ...thProviderAuthorizationListenerInterface.h | 2 + .../Authorization/AuthorizationHandler.h | 206 + .../SampleApp/CarControl/BoolController.h | 0 .../CarControl/CarControlDataProvider.h | 0 .../SampleApp/CarControl/CarControlHandler.h | 208 + .../SampleApp/CarControl/ModeController.h | 0 .../SampleApp/CarControl/RangeController.h | 0 .../Communication/AlexaCommsHandler.h | 121 + .../Connectivity/AlexaConnectivityHandler.h | 160 + .../include/SampleApp/DCM/DCMHandler.h | 16 +- .../{SampleApp => }/include/SampleApp/Event.h | 5 +- .../include/SampleApp/Executor.h | 0 .../include/SampleApp/Extension.h | 13 +- .../LocalSearchProviderHandler.h | 124 + .../Location/LocationProviderHandler.h | 105 + .../include/SampleApp/Logger/LoggerHandler.h | 124 + .../SampleApp/Messaging/MessagingHandler.h | 236 + .../SampleApp/Navigation/NavigationHandler.h | 245 + .../Network/NetworkInfoProviderHandler.h | 111 + .../PhoneControl/PhoneControlHandler.h | 273 + .../PropertyManager/PropertyManagerHandler.h | 126 + .../include/SampleApp/Status.h | 0 .../include/SampleApp/Subject.h | 0 .../{SampleApp => }/include/SampleApp/TTY.h | 0 .../include/SampleApp/TaskQueue.h | 0 .../include/SampleApp/TaskThread.h | 0 .../TextToSpeech/TextToSpeechHandler.h | 158 + .../{SampleApp => }/include/SampleApp/Views.h | 0 samples/cpp/{SampleApp => }/src/Activity.cpp | 0 .../src/AddressBook/AddressBookHandler.cpp | 402 + samples/cpp/src/Alexa/AlertsHandler.cpp | 250 + samples/cpp/src/Alexa/AlexaClientHandler.cpp | 366 + samples/cpp/src/Alexa/AlexaSpeakerHandler.cpp | 219 + samples/cpp/src/Alexa/AudioPlayerHandler.cpp | 266 + samples/cpp/src/Alexa/DeviceSetupHandler.cpp | 120 + samples/cpp/src/Alexa/DoNotDisturbHandler.cpp | 158 + .../src/Alexa/EqualizerControllerHandler.cpp | 195 + .../cpp/src/Alexa/LocalMediaSourceHandler.cpp | 554 + .../Alexa/MediaPlaybackRequestorHandler.cpp | 112 + .../cpp/src/Alexa/NotificationsHandler.cpp | 141 + .../src/Alexa/PlaybackControllerHandler.cpp | 37 +- .../cpp/src/Alexa/SpeechRecognizerHandler.cpp | 227 + .../src/Alexa/SpeechSynthesizerHandler.cpp | 3 +- .../cpp/src/Alexa/TemplateRuntimeHandler.cpp | 298 + .../cpp/{SampleApp => }/src/Application.cpp | 281 +- .../src/ApplicationContext.cpp | 16 +- .../src/Audio/AudioInputProviderHandler.cpp | 174 + .../src/Audio/AudioOutputProviderHandler.cpp | 533 + .../AuthProviderAuthorizationHandler.cpp | 3 +- .../Authorization/AuthorizationHandler.cpp | 481 + .../src/CarControl/CarControlDataProvider.cpp | 0 .../cpp/src/CarControl/CarControlHandler.cpp | 337 + .../src/Communication/AlexaCommsHandler.cpp | 246 + .../Connectivity/AlexaConnectivityHandler.cpp | 453 + .../{SampleApp => }/src/DCM/DCMHandler.cpp | 18 +- samples/cpp/{SampleApp => }/src/Executor.cpp | 0 samples/cpp/{SampleApp => }/src/Extension.cpp | 23 +- .../LocalSearchProviderHandler.cpp | 175 + .../src/Location/LocationProviderHandler.cpp | 179 + samples/cpp/src/Logger/LoggerHandler.cpp | 98 + .../src/Messaging/MessagingHandler.cpp | 128 +- .../cpp/src/Navigation/NavigationHandler.cpp | 683 + .../Network/NetworkInfoProviderHandler.cpp | 162 + .../src/PhoneControl/PhoneControlHandler.cpp | 773 + .../PropertyManagerHandler.cpp | 218 + samples/cpp/{SampleApp => }/src/TaskQueue.cpp | 0 .../cpp/{SampleApp => }/src/TaskThread.cpp | 0 .../src/TextToSpeech/TextToSpeechHandler.cpp | 333 + samples/cpp/{SampleApp => }/src/Views.cpp | 3 +- samples/cpp/src/main.cpp | 269 + tools/aac-tool-a2ml/conanfile.py | 25 + .../aac-tool-a2ml/src/A2ML/a2ml/generator.py | 25 + tools/aac-tool-a2ml/src/A2ML/a2ml/parser.py | 48 + .../src/A2ML/a2ml/templates/interface.tmpl | 64 + .../aac-tool-a2ml/src/A2ML/aasb/generator.py | 194 + .../src/A2ML/aasb/templates/enum.tmpl | 44 + .../src/A2ML/aasb/templates/footer.tmpl | 7 + .../src/A2ML/aasb/templates/header.tmpl | 40 + .../src/A2ML/aasb/templates/message.tmpl | 246 + .../src/A2ML/aasb/templates/struct.tmpl | 48 + .../src/A2ML/markdown/generator.py | 31 + .../A2ML/markdown/templates/interface.tmpl | 198 + tools/aac-tool-a2ml/src/A2ML/model.py | 351 + tools/aac-tool-a2ml/src/A2ML/processor.py | 132 + tools/aac-tool-a2ml/src/a2ml.py | 57 + 4438 files changed, 576805 insertions(+), 258113 deletions(-) create mode 100644 BUILDING.md delete mode 100644 CMakeLists.txt create mode 100644 LICENSE_APACHE_V2 create mode 100644 LINUX_INTEGRATION.md create mode 100644 MIGRATION_TO_AASB_MESSAGEBROKER.md create mode 100644 SDK_MODULES.md create mode 100644 SECURITY.md create mode 100644 aacs/android/README.md rename {platforms => aacs}/android/app-components/alexa-auto-apis/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-apis/README.md create mode 100644 aacs/android/app-components/alexa-auto-apis/build.gradle rename {extensions/bluetooth/aacs/android/modules/aacs-bluetooth => aacs/android/app-components/alexa-auto-apis}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AnimationProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AssistantManager.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/EarconProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SettingsProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupController.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupProvider.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/apl/APLTheme.kt rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaApp.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaAppRootComponent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/ScopedComponent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthController.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthStatus.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt (93%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthorizationHandlerInterface.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/BluetoothDevice.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/ContactsController.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/login/LoginUIEventListener.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/module/ModuleInterface.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionActivityController.java rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionViewController.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupController.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupWorkflowController.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionStatus.kt create mode 100644 aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionsController.java rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/README.md create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/build.gradle rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/gradle.properties (100%) rename {extensions/extras => aacs/android/app-components/alexa-auto-apl-renderer/libs}/.gitignore (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/README.md create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/build.gradle rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/gradle.properties (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/lombok.config (100%) rename {extensions/bluetooth/samples/android/modules/sample-bluetooth => aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render}/proguard-rules.pro (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/settings.gradle (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/AndroidManifest.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLPresenter.java rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java (97%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/audio/AudioFocusController.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java (98%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityContext.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityScope.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationContext.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationScope.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ActivityComponent.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ApplicationComponent.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java (87%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ActivityModule.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ApplicationModule.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/MediaPlayerModule.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/NetworkModule.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/TtsModule.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/ExtensionManager.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackExtension.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStack.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStackDocument.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/IBackCallback.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/localinfo/LocalInfoExtension.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/font/AutoEmbeddedFontResolver.java rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java (87%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLEventSender.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLOptionsBuilderProvider.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLTokenProvider.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IDismissible.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataConsumer.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataReporter.java rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java (76%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java (98%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayerProvider.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/NetworkExecutor.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java (98%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java (95%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/ExecuteCommandPayload.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java (97%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java (98%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderedDocumentStatePayload.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/TimeoutType.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/UserEventPayload.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java (96%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java (96%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/RenderDocumentUtils.java (100%) rename {platforms/android => aacs/android/app-components/alexa-auto-apl-renderer}/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/ViewportUtils.java (100%) rename {platforms/android/app-components/alexa-auto-apl-renderer => aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main}/libs/.gitignore (100%) rename {platforms/android/alexa-auto-client-service/commonutils/aacscommonutils => aacs/android/app-components/alexa-auto-apl-renderer}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/AndroidManifest.xml create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/assets/APLViewport.json rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLDirective.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLFragment.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLThemeDirective.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/Constants.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/handler/APLHandler.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLReceiver.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiver.java create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/layout/fragment_apl.xml create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/values/dimens.xml rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/TestResourceFileReader.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/handler/APLHandlerTest.java rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java (87%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiverTest.java rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json (91%) rename {platforms => aacs}/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json (92%) create mode 100644 aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/UpdateAPLRuntimeProperties.json rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/.gitignore (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/README.md (100%) create mode 100644 aacs/android/app-components/alexa-auto-apps-common-ui/build.gradle rename {platforms/android/alexa-auto-client-service/constants/aacsconstants => aacs/android/app-components/alexa-auto-apps-common-ui}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/CirclePageIndicatorDecoration.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/LoadingDialog.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialog.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/PopupDialogUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/ViewUtils.java (100%) create mode 100755 aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res-placeholders/drawable/alexa_bubble_small.png rename platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/alexa_placeholder_logo.png => aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res-placeholders/drawable/alexa_logo.png (100%) mode change 100644 => 100755 rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/color/radio_button_color_selector.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/ic_close.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/light_button_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/medium_component_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/selected_rect_button_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/small_component_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_button_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_rect_button_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/loading_dialog_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/simple_dialog_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/two_choice_dialog_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/attrs.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/colors.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/dimens.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.app.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/theme-alexa-standard.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-ui/src/test/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialogTest.java (100%) rename {extensions/bluetooth/samples/android/modules/sample-bluetooth => aacs/android/app-components/alexa-auto-apps-common-util}/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/README.md create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/build.gradle rename {platforms/android/alexa-auto-client-service/ipc/aacsipc => aacs/android/app-components/alexa-auto-apps-common-util}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/AndroidManifest.xml create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/Constants.java rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java (95%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/message/AssistantMessage.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/DNDSettingsProvider.java create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/EarconSoundSettingsProvider.java create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/FileUtil.java create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/LocaleUtil.java rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java (90%) rename {platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow => aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common}/util/NetworkUtil.java (96%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/Preconditions.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/UiThemeManager.java rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/AlexaPropertyManager.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/LocalesProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceControllerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/FileUtilTest.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/UiThemeManagerTest.java rename {platforms => aacs}/android/app-components/alexa-auto-apps-common-util/src/test/resources/aacs_config.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-carcontrol/README.md rename {extensions/system-audio/modules/system-audio/lib/aal => aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol}/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/build.gradle rename {platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra => aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/assets/CarControlEndpointMapping.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/AACSCarControlReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlConstants.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHelper.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHandlerTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHelperTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.puml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.puml (100%) create mode 100644 aacs/android/app-components/alexa-auto-carcontrol/build.gradle rename {extensions/bluetooth/aacs/android => aacs/android/app-components/alexa-auto-carcontrol}/gradle.properties (100%) create mode 100644 aacs/android/app-components/alexa-auto-carcontrol/settings.gradle rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/README.md create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/build.gradle rename {platforms/android/app-components/alexa-auto-apis => aacs/android/app-components/alexa-auto-comms-ui}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/AndroidManifest.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/Constants.java create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/ContactsControllerImpl.java rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/PreferenceKeys.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDevice.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDao.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDatabase.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceRepository.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDevice.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDao.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDatabase.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceRepository.java rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/AndroidModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationComponent.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationModule.java rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationPreferenceFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java (96%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModel.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java (91%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiver.java rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/drawable/ic_arrow_right.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout-land/communication_setup_fragment.xml rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_consent_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_pair_new_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_preference_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_settings_fragment.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_setup_fragment.xml rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/navigation/communication_navigation.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-de/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rAU/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rMX/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-hi-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-it/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-ja/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-land/dimens.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-pt-rBR/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/dimens.xml create mode 100644 aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/main/res/xml/communication_preferences.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModelTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandlerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiverTest.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-contacts/README.md rename {platforms/android/app-components/alexa-auto-media-player => aacs/android/app-components/alexa-auto-contacts/aacscontacts}/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-contacts/aacscontacts/build.gradle rename {extensions/bluetooth/aacs/android/modules/aacs-bluetooth => aacs/android/app-components/alexa-auto-contacts/aacscontacts}/consumer-rules.pro (100%) rename {platforms/android/app-components/alexa-auto-apl-renderer => aacs/android/app-components/alexa-auto-contacts/aacscontacts}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/aacscontacts/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/AACSContactsService.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/Constants.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/PhoneBookController.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/app-components/alexa-auto-contacts/aacscontacts}/src/main/res/drawable/alexa_notification_icon.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/aacscontacts/src/test/java/com/amazon/aacscontacts/PhoneBookControllerTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/assets/contactsLib-add.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/assets/contactsLib-add.puml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.puml (100%) create mode 100644 aacs/android/app-components/alexa-auto-contacts/build.gradle rename {platforms/android/alexa-auto-client-service/commonutils => aacs/android/app-components/alexa-auto-contacts}/gradle.properties (100%) create mode 100644 aacs/android/app-components/alexa-auto-contacts/settings.gradle rename {platforms/android/app-components/alexa-auto-navigation => aacs/android/app-components/alexa-auto-device-usage}/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-device-usage/README.md rename {platforms => aacs}/android/app-components/alexa-auto-device-usage/build.gradle (100%) rename {platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra => aacs/android/app-components/alexa-auto-device-usage}/consumer-rules.pro (100%) rename {platforms/android/app-components/alexa-auto-apps-common-ui => aacs/android/app-components/alexa-auto-device-usage}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-device-usage/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/AASBReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/DeviceUsageHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/NetworkStatsManagerRunner.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-device-usage/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-lwa-auth/.gitignore (100%) rename {platforms => aacs}/android/app-components/alexa-auto-lwa-auth/README.md (100%) create mode 100644 aacs/android/app-components/alexa-auto-lwa-auth/build.gradle rename {platforms/android/app-components/alexa-auto-apps-common-util => aacs/android/app-components/alexa-auto-lwa-auth}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-lwa-auth/src/main/AndroidManifest.xml rename {platforms => aacs}/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AlexaClientReceiver.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AuthReceiver.java create mode 100644 aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/CBLAuthReceiver.java create mode 100644 aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthConstants.java create mode 100644 aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthController.java rename {platforms => aacs}/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/TokenStore.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/UserIdentityStore.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-lwa-auth/src/main/res/values/strings.xml (100%) rename {platforms/android/app-components/alexa-auto-templateruntime-renderer => aacs/android/app-components/alexa-auto-media-player}/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/README.md create mode 100644 aacs/android/app-components/alexa-auto-media-player/build.gradle rename {platforms/android/app-components/alexa-auto-comms-ui => aacs/android/app-components/alexa-auto-media-player}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/AndroidManifest.xml rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/Constants.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/MusicStreamAttributeUpdater.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/ShutdownActionReceiver.java create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/AudioPlayerHandler.java create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/IMediaDuckingObserver.java rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/TemplateRuntimeHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java (77%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/content/AlbumArtContentProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AACSModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java (79%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaComponent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java (89%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java (90%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java (98%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaSourceFactory.java rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaState.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java (94%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/PlaylistParser.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProviders.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java (95%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaSessionManager.java rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProvider.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackController.java rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/default_album_image.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike_selected.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_item_place_holder.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like_selected.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat_selected.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle_selected.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_backward_selected.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_forward_selected.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_next_disabled.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_previous_disabled.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/layout/msp_option_view.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-de/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rAU/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rIN/strings.xml rename {platforms/android/app-components/alexa-auto-media-player/src/main/res/values => aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rUS}/strings.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rMX/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/dimens.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/styles.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/values.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-hi-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-it/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-ja/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values-pt-rBR/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values/colors.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values/dimens.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values/integers.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-media-player/src/main/res/values/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values/styles.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/main/res/values/values.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseServiceTest.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusControllerTest.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaMetadataProverTest.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt (93%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProviderTest.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControllerTest.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/RenderPlayerInfoBuilder.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-media-player/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker (100%) rename {samples/android-aacs-sample-app/alexa-auto-app => aacs/android/app-components/alexa-auto-navigation}/.gitignore (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/README.md (100%) create mode 100644 aacs/android/app-components/alexa-auto-navigation/build.gradle rename {platforms/android/app-components/alexa-auto-contacts/aacscontacts => aacs/android/app-components/alexa-auto-navigation}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AACSModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AndroidModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/GoogleMapsModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/NavigationComponent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/ClearTemplateEvent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapter.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/NavigationProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/drawable/circle_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/drawable/ic_cancel.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/drawable/light_info_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/drawable/local_search_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml (98%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_item.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml (96%) create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-de/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rAU/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rIN/strings.xml rename {platforms/android/app-components/alexa-auto-navigation/src/main/res/values => aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rUS}/strings.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rMX/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-hi-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-it/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-ja/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/values-land/dimens.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values-pt-rBR/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values/dimens.xml rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/values/ids.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-navigation/src/main/res/values/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/main/res/values/styles.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandlerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandlerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapterTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProviderTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiverTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiverTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/TestResourceFileReader.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/resources/aacs/CancelNavigation.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/resources/aacs/ClearTemplate.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/resources/aacs/GetNavigationState.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchDetail.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchList.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-navigation/src/test/resources/aacs/StartNavigation.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-settings/README.md create mode 100644 aacs/android/app-components/alexa-auto-settings/build.gradle rename {platforms/android/app-components/alexa-auto-device-usage => aacs/android/app-components/alexa-auto-settings}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/AndroidManifest.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/assets/locales.json rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java (88%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSPreferenceFragment.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSettingsLanguagesFragment.java create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragment.java create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDChangeMessage.java create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDReceiver.java rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java (96%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java (83%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfiguration.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurationPreferences.kt (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java (98%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/PreferenceKeys.java rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AACSModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AndroidModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/ConfigModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/MenuModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java (83%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java (90%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsScreenBuilder.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java (85%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilder.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilder.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_arrow_back.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_check.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_last_preference_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_preference_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/layout/navigation_bar_layout.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/layout/settings_activity_layout.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/layout/settings_alexa_language_layout.xml rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml (77%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-de/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rAU/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-en/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rMX/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-es/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-hi-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-it/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-ja/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values-pt-rBR/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/values/dimens.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/values/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/values/styles.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/xml/aacs_preferences.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml (88%) create mode 100644 aacs/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_sound_preferences.xml create mode 100644 aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragmentTest.java rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java (94%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilderTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilderTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilderTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/README.md create mode 100644 aacs/android/app-components/alexa-auto-setup/build.gradle rename {platforms/android/app-components/alexa-auto-lwa-auth => aacs/android/app-components/alexa-auto-setup}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/CBLLoginWorkflowSpecification.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/PreviewModeLoginWorkflowSpecification.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/AndroidModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/ConfigModule.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/SetupComponent.java rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/WorkflowModule.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/receiver/NetworkStateChangeReceiver.java rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/AlexaSetupWorkflowControllerImpl.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/Workflow.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowMessage.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigator.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowProvider.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowStep.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckContactsConsentStatusCommand.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLanguageCommand.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommand.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java (97%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckNetworkStatusCommand.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/Command.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommand.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/LoginEvent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/VoiceAssistanceEvent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java (84%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java (90%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragment.java rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeViewModel.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java (86%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModel.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkViewModel.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragment.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/model/LocationConsent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/QRCodeGenerator.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/drawable/ic_wifi_help.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/auth_provider_login_finished.xml rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_code_loading.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_error.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_finished.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/enable_preview_mode.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/location_consent.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_display_cbl_code.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_start.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/network_fragment.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/setup_not_complete.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/start_language_selection.xml rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/layout/aacs_connection_loading.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/auth_provider_login_finished.xml rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_code_loading.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_fragment.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_error.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_finished.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/enable_preview_mode.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/location_consent.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_display_cbl_code.xml rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/layout/login_fragment.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_start.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/network_fragment.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/setup_not_complete.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/layout/start_language_selection.xml rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml (97%) create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-de/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rAU/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-en/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rMX/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rUS/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-es/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr-rCA/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-hi-rIN/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-it/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-ja/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-land/dimens.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values-pt-rBR/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values/dimens.xml create mode 100644 aacs/android/app-components/alexa-auto-setup/src/main/res/values/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/TestResourceFileReader.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigatorTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowProviderTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommandTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommandTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java (85%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModelTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragmentTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/receiver/NetworkStateChangeReceiverTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-setup/src/test/resources/workflowSpecification/CBLLoginWorkflowSpecification.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-telephony/README.md rename {platforms/android/alexa-auto-client-service/commonutils/aacscommonutils => aacs/android/app-components/alexa-auto-telephony/aacstelephony}/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-telephony/aacstelephony/build.gradle rename {platforms/android/alexa-auto-client-service/commonutils/aacscommonutils => aacs/android/app-components/alexa-auto-telephony/aacstelephony}/consumer-rules.pro (100%) rename {platforms/android/app-components/alexa-auto-media-player => aacs/android/app-components/alexa-auto-telephony/aacstelephony}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/androidTest/java/com/amazon/aacstelephony/ExampleInstrumentedTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java (85%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java (98%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallMap.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallStateListener.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Constants.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/PhoneCallController.java rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java (92%) rename {platforms/android/app-components/alexa-auto-contacts/aacscontacts => aacs/android/app-components/alexa-auto-telephony/aacstelephony}/src/main/res/drawable/alexa_notification_icon.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/test/java/com/amazon/aacstelephony/BluetoothStateListenerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/test/java/com/amazon/aacstelephony/CallStateListenerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/aacstelephony/src/test/java/com/amazon/aacstelephony/PhoneCallControllerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/assets/AACSTelephony_initiateCall.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-telephony/assets/AACSTelephony_initiateCall.puml (100%) create mode 100644 aacs/android/app-components/alexa-auto-telephony/build.gradle rename {platforms/android/alexa-auto-client-service/constants => aacs/android/app-components/alexa-auto-telephony}/gradle.properties (100%) create mode 100644 aacs/android/app-components/alexa-auto-telephony/settings.gradle create mode 100644 aacs/android/app-components/alexa-auto-templateruntime-renderer/.gitignore rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/README.md (100%) create mode 100644 aacs/android/app-components/alexa-auto-templateruntime-renderer/build.gradle rename {platforms/android/app-components/alexa-auto-navigation => aacs/android/app-components/alexa-auto-templateruntime-renderer}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AACSModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AndroidModule.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/TemplateRuntimeComponent.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaVoiceoverCompletedMessage.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapter.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java (97%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/display_card_background.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/ic_cancel.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather.xml rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_current.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast_day.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values-land/dimens.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/dimens.xml rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/ids.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/styles.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/common/TestResourceFileReader.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiverTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiverTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapterTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandlerTest.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/ClearTemplate.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedIdle.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedListening.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/RenderTemplateWeather.json (100%) create mode 100644 aacs/android/app-components/alexa-auto-tts/README.md create mode 100644 aacs/android/app-components/alexa-auto-tts/aacstts/.gitignore create mode 100644 aacs/android/app-components/alexa-auto-tts/aacstts/build.gradle rename {platforms/android/app-components/alexa-auto-settings => aacs/android/app-components/alexa-auto-tts/aacstts}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AACSUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AmazonTextToSpeechService.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AudioDecoder.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/ISO3CodeUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/JSONUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/MessageHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/SynthesizeTextUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSConstants.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSIntentReceiver.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AASBHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AlexaClientHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/IAACSMessageHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/TTSHandler.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/GetCapabilitiesPayload.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessageOptions.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessagePayload.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/ProviderVoiceItem.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/TTSSynthesisFutureResponse.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AlexaClientHandlerTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AmazonTextToSpeechServiceTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/SynthesizeTextUtilTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TTSHandlerTests.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TestAACSUtil.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/assets/Android_TTS.png (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/assets/Android_TTS.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-tts/build.gradle rename {platforms/android/app-components/alexa-auto-carcontrol => aacs/android/app-components/alexa-auto-tts}/gradle.properties (100%) rename {platforms => aacs}/android/app-components/alexa-auto-tts/settings.gradle (100%) create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/.gitignore create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/README.md create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/build.gradle rename {platforms/android/app-components/alexa-auto-setup => aacs/android/app-components/alexa-auto-ux-restrictions}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/src/main/AndroidManifest.xml create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/src/main/assets/aacs-sample-app/modules-uxrestrictions.json create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/CarUxRestrictionsModule.java create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/DefaultCarUxRestrictionsController.java create mode 100644 aacs/android/app-components/alexa-auto-ux-restrictions/src/main/res/values/strings.xml rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/.gitignore (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-interaction/README.md create mode 100644 aacs/android/app-components/alexa-auto-voice-interaction/build.gradle rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/gradle.properties (100%) rename {platforms/android/app-components/alexa-auto-telephony/aacstelephony => aacs/android/app-components/alexa-auto-voice-interaction}/proguard-rules.pro (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/AndroidManifest.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/AutoVoiceInteractionMessage.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/Constants.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiver.java rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java (85%) create mode 100644 aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSession.java rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSessionService.java (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/res/values/strings.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/main/res/xml/auto_voice_interaction_service.xml (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/TestResourceFileReader.java (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiverTest.java rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedConnected.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedDisconnected.json (100%) rename {platforms => aacs}/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/WakewordDetected.json (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/.gitignore create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/README.md create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/build.gradle rename {samples/android-aacs-sample-app => aacs/android/app-components/alexa-auto-voice-ui}/gradle.properties (100%) rename {platforms/android/app-components/alexa-auto-templateruntime-renderer => aacs/android/app-components/alexa-auto-voice-ui}/proguard-rules.pro (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/AndroidManifest.xml create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/VoiceActivity.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/AutoVoiceUIMessage.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/Constants.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/earcon/EarconController.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiver.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImpl.java rename {platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction => aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui}/session/SessionViewControllerImpl.java (96%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/main/res/layout/autovoiceinteraction_layout.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-de/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rAU/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rCA/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rIN/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rUS/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-es-rMX/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-es-rUS/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-es/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-fr-rCA/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-fr/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-hi-rIN/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-it/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-ja/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-pt-rBR/auto_error_offline.mp3 create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/auto_error_offline.mp3 rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/main/res/raw/med_ui_endpointing.wav (100%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/main/res/raw/med_ui_wakesound.wav (100%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/main/res/raw/med_ui_wakesound_touch.wav (100%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/main/res/values-land/dimens.xml (100%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/main/res/values/dimens.xml (100%) create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/strings.xml create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/styles.xml create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/TestResourceFileReader.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiverTest.java create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImplTest.java rename {platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction => aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui}/session/SessionViewControllerImplTest.java (97%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/test/resources/aacs/DialogStateChangedIdle.json (91%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/test/resources/aacs/DialogStateChangedListening.json (91%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/test/resources/aacs/DialogStateChangedSpeaking.json (91%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/app-components/alexa-auto-voice-ui}/src/test/resources/aacs/DialogStateChangedThinking.json (91%) create mode 100644 aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/WakewordDetected.json rename {platforms/android/alexa-auto-client-service => aacs/android}/assets/AACSArchDetailed.png (100%) rename {platforms/android/alexa-auto-client-service => aacs/android}/assets/AACSInit.puml (100%) rename {platforms/android/alexa-auto-client-service => aacs/android}/assets/AACSInitFlow.png (100%) rename {platforms/android/alexa-auto-client-service => aacs/android}/assets/AACSWakeword.png (100%) rename {platforms/android/alexa-auto-client-service => aacs/android}/assets/AACSWakeword.puml (100%) create mode 100644 aacs/android/assets/AACS_CBLLogin.png create mode 100644 aacs/android/assets/AACS_CBLLogin.puml rename {platforms/android/alexa-auto-client-service => aacs/android}/assets/APCP.png (100%) create mode 100644 aacs/android/assets/config.json rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/.gitignore (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/README.md (100%) rename {platforms/android/alexa-auto-client-service/constants/aacsconstants => aacs/android/common/commonutils/aacscommonutils}/.gitignore (100%) create mode 100644 aacs/android/common/commonutils/aacscommonutils/build.gradle rename {platforms/android/alexa-auto-client-service/constants/aacsconstants => aacs/android/common/commonutils/aacscommonutils}/consumer-rules.pro (100%) rename {platforms/android/app-components/alexa-auto-tts/aacstts => aacs/android/common/commonutils/aacscommonutils}/proguard-rules.pro (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/AndroidManifest.xml (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSComponentRegistryUtil.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessage.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java (98%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageSender.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSReplyMessage.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessages.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessages.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchCommon.kt (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchDetailTemplate.kt (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchListTemplate.kt (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/NavigationMessages.java (100%) create mode 100644 aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessages.java rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt (87%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessages.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/StartNavigation.kt (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessages.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WakewordDetectedMessages.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WeatherTemplate.kt (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilderTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageSenderTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessagesTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessagesTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/NavigationMessagesTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessagesTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessagesTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessagesTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TestResourceFileReader.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchDetailTemplateV1.json (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchListTemplateV2.json (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/resources/aacs/StartNavigation.json (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/commonutils/aacscommonutils/src/test/resources/aacs/TemplateRuntimePlayerRenderInfo.json (100%) create mode 100644 aacs/android/common/commonutils/build.gradle rename {platforms/android/app-components/alexa-auto-contacts => aacs/android/common/commonutils}/gradle.properties (100%) create mode 100644 aacs/android/common/commonutils/settings.gradle rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/.gitignore (100%) rename {platforms/android/alexa-auto-client-service/ipc/aacsipc => aacs/android/common/constants/aacsconstants}/.gitignore (100%) create mode 100644 aacs/android/common/constants/aacsconstants/build.gradle rename {platforms/android/app-components/alexa-auto-contacts/aacscontacts => aacs/android/common/constants/aacsconstants}/consumer-rules.pro (100%) rename {platforms/android/app-components/alexa-auto-voice-interaction => aacs/android/common/constants/aacsconstants}/proguard-rules.pro (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/androidTest/java/com/amazon/aacsconstants/ExampleInstrumentedTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/AndroidManifest.xml (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java (87%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java (96%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java (89%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java (92%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/ContactsConstants.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java (86%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NavigationConstants.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NetworkConstants.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java (76%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java (91%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TemplateRuntimeConstants.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java (94%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/aacsconstants/src/test/java/com/amazon/aacsconstants/ExampleUnitTest.java (100%) create mode 100644 aacs/android/common/constants/build.gradle rename {platforms/android/app-components/alexa-auto-telephony => aacs/android/common/constants}/gradle.properties (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/constants/settings.gradle (100%) rename {extensions/bluetooth/aacs/android => aacs/android/common/ipc}/.gitignore (100%) create mode 100644 aacs/android/common/ipc/README.md rename {platforms/android/app-components/alexa-auto-apps-common-util => aacs/android/common/ipc/aacsipc}/.gitignore (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/build.gradle (100%) rename {platforms/android/modules/apl-render => aacs/android/common/ipc/aacsipc}/proguard-rules.pro (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/androidTest/java/com/amazon/aacsipc/ExampleInstrumentedTest.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/AndroidManifest.xml (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSPinger.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSReceiver.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java (97%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/java/com/amazon/aacsipc/IPCConstants.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/java/com/amazon/aacsipc/SenderMap.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/main/java/com/amazon/aacsipc/TargetComponent.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/test/java/com/amazon/aacsipc/DummyService.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSReceiver.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSSender.java (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestUtils.java (100%) create mode 100644 aacs/android/common/ipc/build.gradle rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/gradle.properties (100%) rename {platforms/android/alexa-auto-client-service => aacs/android/common}/ipc/settings.gradle (100%) create mode 100644 aacs/android/conanfile.py create mode 100644 aacs/android/restrictedAssets/LICENSE_PMLA create mode 100644 aacs/android/restrictedAssets/NOTICE create mode 100644 aacs/android/restrictedAssets/drawable/alexa_bubble_small.png create mode 100644 aacs/android/restrictedAssets/drawable/alexa_logo.png rename {samples/android-aacs-sample-app => aacs/android/sample-app}/.gitignore (100%) create mode 100644 aacs/android/sample-app/README.md create mode 100644 aacs/android/sample-app/alexa-auto-app/.gitignore rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/assets/AACSSampleAppArch.png (100%) create mode 100644 aacs/android/sample-app/alexa-auto-app/assets/AACSSampleAppComponentDiagram.drawio create mode 100644 aacs/android/sample-app/alexa-auto-app/assets/AACSSampleAppComponentDiagram.png create mode 100644 aacs/android/sample-app/alexa-auto-app/build.gradle rename {platforms/android/alexa-auto-client-service/android-service => aacs/android/sample-app/alexa-auto-app}/gradle.properties (100%) rename {platforms/android/modules/maccandroid => aacs/android/sample-app/alexa-auto-app}/proguard-rules.pro (100%) create mode 100644 aacs/android/sample-app/alexa-auto-app/src/main/AndroidManifest.xml create mode 100644 aacs/android/sample-app/alexa-auto-app/src/main/assets/config/aacs_config.json rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/AutoApplication.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/Constants.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/DefaultAlexaAppRootComponent.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/audio/AudioIOService.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/audio/AudioIOServiceWorker.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/audio/AudioInputHandler.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/audio/AudioInputReader.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/audio/AudioServiceNotificationBuilder.java (91%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AACSModule.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AlexaAppModule.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AlexaAppScope.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AndroidAppModule.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AppComponent.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AudioIOComponent.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/AudioIOModule.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/dependencies/ServiceScope.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/java/com/amazon/alexa/auto/app/setup/AlexaSetupControllerImpl.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/res/values/strings.xml (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/main/res/xml/filepaths.xml (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/test/java/com/amazon/alexa/auto/app/audio/AudioIOServiceTest.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/test/java/com/amazon/alexa/auto/app/audio/AudioInputHandlerTest.java (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/alexa-auto-app/src/test/java/com/amazon/alexa/auto/app/audio/AudioInputReaderTest.java (100%) create mode 100644 aacs/android/sample-app/build.gradle create mode 100755 aacs/android/sample-app/gradle.properties rename {samples/android-aacs-sample-app => aacs/android/sample-app}/gradle/wrapper/gradle-wrapper.jar (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/gradle/wrapper/gradle-wrapper.properties (100%) rename {samples/android-aacs-sample-app => aacs/android/sample-app}/gradlew (100%) create mode 100644 aacs/android/sample-app/settings.gradle create mode 100755 aacs/android/service/.gitignore create mode 100644 aacs/android/service/README.md create mode 100755 aacs/android/service/build.gradle rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/.gitignore (100%) create mode 100644 aacs/android/service/core-service/build.gradle create mode 100644 aacs/android/service/core-service/src/androidTest/assets/file-util-res/aacs_config.json rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/androidTest/assets/file-util-res/auto_sdk_config.json (94%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/androidTest/java/com/amazon/alexaautoclientservice/instrumentedtest/TestAlexaAutoClientService.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/androidTest/java/com/amazon/alexaautoclientservice/instrumentedtest/TestFileUtil.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/androidTest/java/com/amazon/alexaautoclientservice/instrumentedtest/TestUtil.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/debug/AndroidManifest.xml (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/debug/java/com/amazon/alexaautoclientservice/AACSMessageLogger.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/debug/java/com/amazon/alexaautoclientservice/README.md (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/debug/java/com/amazon/alexaautoclientservice/constants/MessageLoggerConstants.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/debug/java/com/amazon/alexaautoclientservice/receiver/InstrumentationReceiver.java (100%) create mode 100644 aacs/android/service/core-service/src/main/AndroidManifest.xml rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/aidl/com/amazon/alexalve/ILVCClient.aidl (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/aidl/com/amazon/alexalve/ILVCService.aidl (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/09789157.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/3513523f.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/6d41d539.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/85cf5865.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/8cb5ee0f.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/b204d74a.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/ce5e74ef.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/de6d66f3.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/assets/certs/f387163d.0 (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/AACSPropertyContentProvider.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/AASBHandler.java (82%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/AlexaAutoClientService.java (90%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/ComponentRegistry.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/ConfigMessageReceivedCallback.java (89%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/LVCInteractionProvider.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/NotificationListener.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/constants/AudioSourceConstants.java (100%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/constants/ConfigFieldConstants.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/constants/LVCServiceConstants.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/alexaClient/AlexaClientMessageHandler.java (75%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/alexaClient/AuthStateObserver.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/alexaClient/ConnectionStateObserver.java (100%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/alexaClient/DialogStateObserver.java create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioInput/AudioInputFocusManager.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/audioInput/AudioInputMessageHandler.java (98%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput/AudioOutputMessageHandler.java (92%) rename {platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput}/mediaPlayer/AACSMediaPlayer.java (94%) rename {platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput}/mediaPlayer/AudioFocusAttributes.java (94%) rename {platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput}/mediaPlayer/EventReceiver.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput}/mediaPlayer/exo/ExoPlayerHandler.java (77%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput/mediaPlayer/exo/MediaSourceFactory.java create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput/mediaPlayer/exo/PlaylistParser.java create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/audioOutput/mediaPlayer/raw/RawAudioOutputHandler.java rename {extensions/bluetooth/aacs/android/modules/aacs-bluetooth/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules}/bluetooth/BluetoothProviderHandler.java (96%) rename {extensions/bluetooth/aacs/android/modules/aacs-bluetooth/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules}/bluetooth/BluetoothServerSocketHandler.java (97%) rename {extensions/bluetooth/aacs/android/modules/aacs-bluetooth/src/main/java/com/amazon/alexaautoclientservice => aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules}/bluetooth/BluetoothSocketHandler.java (96%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/customDomain/CustomDomainMessageDispatcher.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/externalMediaPlayer/IDiscoveredPlayerProvider.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/externalMediaPlayer/MACCPlayer.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/locationProvider/LocationProviderHandler.java (100%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/mediaManager/LocalMediaSourceHandler.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/mediaManager/LocalSessionHandler.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/mediaManager/MediaSource.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/modules/networkInfoProvider/NetworkInfoProviderHandler.java (100%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/modules/propertyManager/PropertyManagerHandler.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/receiver/LVCReceiver.java (97%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/receiver/PingReceiver.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/receiver/ServiceMetadataRequestReceiver.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/receiver/StartOnBootReceiver.java (100%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/receiver/SystemPropertyChangeReceiver.java rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/util/AACSStateObserver.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/java/com/amazon/alexaautoclientservice/util/AASBUtil.java (100%) create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/util/FileUtil.java create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/util/MediaPlayerUtil.java create mode 100644 aacs/android/service/core-service/src/main/java/com/amazon/alexaautoclientservice/util/PropertyUtil.java rename {platforms/android/app-components/alexa-auto-telephony/aacstelephony => aacs/android/service/core-service}/src/main/res/drawable/alexa_notification_icon.png (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/main/res/values/strings.xml (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/release/java/com/amazon/alexaautoclientservice/AACSMessageLogger.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/release/java/com/amazon/alexaautoclientservice/receiver/InstrumentationReceiver.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/service => aacs/android/service/core-service}/src/test/java/com/amazon/alexaautoclientservice/unittest/TestAASBHandler.java (100%) create mode 100755 aacs/android/service/gradle.properties rename {samples/android => aacs/android/service}/gradle/wrapper/gradle-wrapper.jar (100%) rename {samples/android => aacs/android/service}/gradle/wrapper/gradle-wrapper.properties (80%) rename {samples/android => aacs/android/service}/gradlew (100%) mode change 100644 => 100755 create mode 100644 aacs/android/service/modules/aacs-extra/build.gradle rename {platforms/android/app-components/alexa-auto-device-usage => aacs/android/service/modules/aacs-extra}/consumer-rules.pro (100%) rename {platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol => aacs/android/service/modules/aacs-extra}/proguard-rules.pro (100%) rename {platforms/android/alexa-auto-client-service/android-service => aacs/android/service}/modules/aacs-extra/src/main/AndroidManifest.xml (100%) rename {platforms/android/alexa-auto-client-service/android-service => aacs/android/service}/modules/aacs-extra/src/main/java/com/amazon/alexaautoclientservice/aacs_extra/AACSContext.java (100%) rename {platforms/android/alexa-auto-client-service/android-service => aacs/android/service}/modules/aacs-extra/src/main/java/com/amazon/alexaautoclientservice/aacs_extra/AACSModuleFactoryInterface.java (100%) rename {platforms/android/alexa-auto-client-service/android-service => aacs/android/service}/modules/aacs-extra/src/main/java/com/amazon/alexaautoclientservice/aacs_extra/EngineStatusListener.java (100%) rename {platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra => aacs/android/service/modules/maccandroid}/.gitignore (100%) create mode 100644 aacs/android/service/modules/maccandroid/build.gradle rename {samples/android-aacs-sample-app/alexa-auto-app => aacs/android/service/modules/maccandroid}/proguard-rules.pro (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/AndroidManifest.xml (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/DiscoverAndReportMediaAppsHandler.java (99%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/Log.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MACCAndroidClient.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MACCAndroidClientCallback.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MediaApp.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MediaAppsConnectionListener.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MediaAppsDirectivesHandler.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MediaAppsRepository.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MediaAppsStateReporter.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/MediaControllerCallback.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/APIConstants.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/AdjustSeekDirective.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/Directive.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/LoginDirective.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/LogoutDirective.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/PlayControlDirective.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/PlayDirective.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/Directive/SeekDirective.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/PackageMetadata.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/PlayBackStateFields.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/PlayerEvents.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/PlayerPlaybackInfo.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/SupportedOperations.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/errors/CapabilityAgentError.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/errors/MediaAppPlayerError.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/players/AuthorizedPlayer.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/players/DiscoveredPlayer.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/state/ExternalMediaPlayerState.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/state/MediaAppMetaData.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/state/MediaAppPlaybackState.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/main/java/com/amazon/maccandroid/model/state/MediaAppSessionState.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/DiscoverAndReportMediaAppsHandlerTest.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/ExampleUnitTest.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/MediaAppsDirectivesHandlerTest.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/MediaAppsRepositoryTest.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/MediaControllerCallbackTest.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/ShadowJobInfo.java (100%) rename {platforms/android => aacs/android/service}/modules/maccandroid/src/test/java/com/amazon/maccandroid/ShadowUri.java (100%) create mode 100755 aacs/android/service/settings.gradle create mode 100644 assets/Migration-ApplicationArch.png create mode 100644 assets/Migration-Hybrid.png create mode 100644 assets/Migration-Steps.png delete mode 100644 assets/aac_architecture.png create mode 100644 assets/aac_linux_integration.png create mode 100755 builder/build.py delete mode 100755 builder/build.sh delete mode 100755 builder/hosttools/pkg-config delete mode 100644 builder/hosttools/qnx7-pkgconfig/aarch64le/libcrypto.pc delete mode 100644 builder/hosttools/qnx7-pkgconfig/x86_64/libcrypto.pc delete mode 100644 builder/meta-aac-builder/classes/aac-base.bbclass delete mode 100644 builder/meta-aac-builder/classes/aac-image.bbclass delete mode 100644 builder/meta-aac-builder/conf/conf-notes.txt delete mode 100644 builder/meta-aac-builder/conf/distro/aac.conf delete mode 100644 builder/meta-aac-builder/conf/distro/include/tclibc-android.inc delete mode 100644 builder/meta-aac-builder/conf/distro/include/tclibc-qnx.inc delete mode 100644 builder/meta-aac-builder/conf/distro/include/tcmode-external.inc delete mode 100644 builder/meta-aac-builder/conf/layer.conf delete mode 100644 builder/meta-aac-builder/conf/local.conf.sample delete mode 100644 builder/meta-aac-builder/conf/machine/androidarm.conf delete mode 100644 builder/meta-aac-builder/conf/machine/androidarm64.conf delete mode 100644 builder/meta-aac-builder/conf/machine/androidx86-64.conf delete mode 100644 builder/meta-aac-builder/conf/machine/androidx86.conf delete mode 100644 builder/meta-aac-builder/conf/machine/include/android.inc delete mode 100644 builder/meta-aac-builder/conf/machine/include/linaro.inc delete mode 100644 builder/meta-aac-builder/conf/machine/include/poky.inc delete mode 100644 builder/meta-aac-builder/conf/machine/include/qnx7.inc delete mode 100644 builder/meta-aac-builder/conf/machine/linaroarm64.conf delete mode 100644 builder/meta-aac-builder/conf/machine/linaroarmel.conf delete mode 100644 builder/meta-aac-builder/conf/machine/linaroarmhf.conf delete mode 100644 builder/meta-aac-builder/conf/machine/native.conf delete mode 100644 builder/meta-aac-builder/conf/machine/pokyarm.conf delete mode 100644 builder/meta-aac-builder/conf/machine/pokyarm64.conf delete mode 100644 builder/meta-aac-builder/conf/machine/qnx7arm64.conf delete mode 100644 builder/meta-aac-builder/conf/machine/qnx7x86-64.conf delete mode 100644 builder/meta-aac-builder/recipes-connectivity/mbedtls/mbedtls_2.16.2.bb delete mode 100644 builder/meta-aac-builder/recipes-connectivity/nghttp2/nghttp2_%.bbappend delete mode 100644 builder/meta-aac-builder/recipes-connectivity/openssl/openssl_1.1.0%.bbappend delete mode 100644 builder/meta-aac-builder/recipes-core/images/aac-sdk-build.bb delete mode 100755 builder/meta-aac-builder/recipes-devtools/asio/asio_1.12.2.bb delete mode 100644 builder/meta-aac-builder/recipes-devtools/cmake/cmake-native_3.8.2.bb delete mode 100644 builder/meta-aac-builder/recipes-devtools/nlohmann/nlohmann_3.7.1.bb delete mode 100644 builder/meta-aac-builder/recipes-devtools/protobuf/protobuf_%.bbappend delete mode 100644 builder/meta-aac-builder/recipes-devtools/rapidjson/rapidjson_1.1.0.bb delete mode 100755 builder/meta-aac-builder/recipes-devtools/websocketpp/websocketpp_0.8.1.bb delete mode 100644 builder/meta-aac-builder/recipes-support/curl/curl_7.65.3.bb delete mode 100644 builder/meta-aac-builder/recipes-support/sqlite/sqlite3_%.bbappend delete mode 100644 builder/meta-aac-ubuntu/classes/hostnativepackage.bbclass delete mode 100644 builder/meta-aac-ubuntu/classes/python3native.bbclass delete mode 100644 builder/meta-aac-ubuntu/conf/layer.conf delete mode 100644 builder/meta-aac-ubuntu/recipes-native/db/db-native.bb delete mode 100644 builder/meta-aac-ubuntu/recipes-native/expat/expat-native.bb delete mode 100644 builder/meta-aac-ubuntu/recipes-native/libarchive/libarchive-native.bb delete mode 100644 builder/meta-aac-ubuntu/recipes-native/popt/popt-native.bb delete mode 100644 builder/meta-aac-ubuntu/recipes-native/zlib/zlib-native.bb delete mode 100644 builder/meta-aac/README.md delete mode 100644 builder/meta-aac/classes/aac-module.bbclass delete mode 100644 builder/meta-aac/classes/devlibsonly.bbclass delete mode 100644 builder/meta-aac/classes/unittests.bbclass delete mode 100644 builder/meta-aac/conf/layer.conf delete mode 100644 builder/meta-aac/custom-licenses/ASL-1.0 delete mode 100644 builder/meta-aac/lib/aac/__init__.py delete mode 100644 builder/meta-aac/recipes-apl/apl-core-library/apl-core-library_git.bb delete mode 100644 builder/meta-aac/recipes-avs/avs-device-sdk/avs-device-sdk-1.22.0/0001-Auto-SDK-Changes-for-v1.22-AVS-SDK.patch delete mode 100644 builder/meta-aac/recipes-avs/avs-device-sdk/avs-device-sdk.inc delete mode 100644 builder/meta-aac/recipes-avs/avs-device-sdk/avs-device-sdk_1.22.0.bb delete mode 100644 builder/meta-aac/recipes-avs/smart-screen-sdk/smart-screen-sdk/0001-Smart-Screen-SDK-for-Alexa-Auto-SDK.patch delete mode 100644 builder/meta-aac/recipes-avs/smart-screen-sdk/smart-screen-sdk/0002-Disable-SmartScreenCapabilityAgents-test.patch delete mode 100644 builder/meta-aac/recipes-avs/smart-screen-sdk/smart-screen-sdk_git.bb delete mode 100644 builder/meta-aac/recipes-connectivity/nghttp2/nghttp2_1.39.1.bb delete mode 100644 builder/meta-aac/recipes-devtools/googletest/googletest_1.8.0.bb delete mode 100644 builder/meta-aac/recipes-devtools/protobuf/protobuf/0001-Makefile.am-include-descriptor.cc-when-building-libp.patch delete mode 100644 builder/meta-aac/recipes-devtools/protobuf/protobuf/0001-protobuf-fix-configure-error.patch delete mode 100644 builder/meta-aac/recipes-devtools/protobuf/protobuf_3.9.0.bb delete mode 100644 builder/meta-aac/recipes-multimedia/libopus/libopus_1.3.1.bb delete mode 100644 builder/meta-aac/recipes-support/curl/curl_%.bbappend delete mode 100644 builder/meta-aac/recipes-wakeword/snowboy/snowboy_1.3.0.bb create mode 100644 builder/pylib/build_cmd.py create mode 100644 builder/pylib/clean_cmd.py create mode 100644 builder/pylib/common.py create mode 100644 builder/pylib/configure_cmd.py create mode 100644 builder/pylib/imports_cmd.py delete mode 100644 builder/scripts/Dockerfile delete mode 100755 builder/scripts/agreement.sh delete mode 100644 builder/scripts/common.sh delete mode 100755 builder/scripts/gen-version.sh delete mode 100755 builder/scripts/run-aacs-android.sh delete mode 100755 builder/scripts/run-bitbake.sh delete mode 100755 builder/scripts/run-builder.sh delete mode 100755 builder/scripts/run-docker.sh delete mode 100755 builder/scripts/run-gradle.sh delete mode 100755 builder/scripts/setup-android-toolchain.sh delete mode 100644 builder/scripts/version create mode 100644 conan/config/profiles/aac-android create mode 100644 conan/config/profiles/aac-linux create mode 100644 conan/config/profiles/aac-macos create mode 100644 conan/config/profiles/aac-mingw create mode 100644 conan/config/profiles/aac-poky create mode 100644 conan/config/profiles/aac-qnx create mode 100644 conan/config/remotes.txt create mode 100644 conan/docker/aac-ubuntu-bionic/Dockerfile create mode 100644 conan/docker/aac-ubuntu-focal/Dockerfile create mode 100644 conan/recipes/aac-sdk-tools/CMakeLists.txt create mode 100644 conan/recipes/aac-sdk-tools/build.gradle rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/09789157.0 (100%) mode change 100644 => 100755 rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/3513523f.0 (100%) rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/6d41d539.0 (100%) mode change 100644 => 100755 rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/85cf5865.0 (100%) rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/8cb5ee0f.0 (100%) mode change 100644 => 100755 rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/b204d74a.0 (100%) mode change 100644 => 100755 rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/ce5e74ef.0 (100%) mode change 100644 => 100755 rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/de6d66f3.0 (100%) mode change 100644 => 100755 rename {samples/android/app/src/main/assets => conan/recipes/aac-sdk-tools}/certs/f387163d.0 (100%) mode change 100644 => 100755 create mode 100644 conan/recipes/aac-sdk-tools/cmake/001-aac-base-module.cmake create mode 100644 conan/recipes/aac-sdk-tools/conanfile.py create mode 100644 conan/recipes/aac-sdk-tools/gradle/gradle.properties create mode 100644 conan/recipes/aac-sdk-tools/pylib/a2ml_build.py create mode 100644 conan/recipes/aac-sdk-tools/pylib/cmake_build.py create mode 100644 conan/recipes/aac-sdk-tools/pylib/ddl_build.py create mode 100644 conan/recipes/aac-sdk-tools/pylib/gradle_build.py create mode 100644 conan/recipes/aac-sdk-tools/pylib/utils.py create mode 100755 conan/recipes/android-sdk-tools/cmake-wrapper create mode 100644 conan/recipes/android-sdk-tools/cmake-wrapper.cmd create mode 100644 conan/recipes/android-sdk-tools/conanfile.py create mode 100644 conan/recipes/apl-core/conanfile.py create mode 100644 conan/recipes/avs-device-sdk/conanfile.py create mode 100644 conan/recipes/avs-device-sdk/patches/0001-Alexa-Auto-SDK-Changes-for-v1.25.0-AVS-SDK.patch create mode 100644 conan/recipes/cheetah/conanfile.py create mode 100644 conan/recipes/cheetah/patches/fix_namemapper_warning.patch create mode 100644 conan/recipes/faad2/conanfile.py create mode 100644 conan/recipes/glib-networking/conanfile.py create mode 100644 conan/recipes/glib/conandata.yml create mode 100644 conan/recipes/glib/conanfile.py create mode 100644 conan/recipes/gradle/conanfile.py create mode 100644 conan/recipes/gst-plugins-bad/conandata.yml create mode 100644 conan/recipes/gst-plugins-bad/conanfile.py create mode 100644 conan/recipes/gst-plugins-bad/patches/0001-Remove-unnecessary-stuff.patch create mode 100644 conan/recipes/gst-plugins-base/conandata.yml create mode 100644 conan/recipes/gst-plugins-base/conanfile.py create mode 100644 conan/recipes/gst-plugins-good/conandata.yml create mode 100644 conan/recipes/gst-plugins-good/conanfile.py create mode 100644 conan/recipes/gst-plugins-good/patches/0001-Resolve-gst-multifile-test-splitmuxpartreader-link-e.patch create mode 100644 conan/recipes/gst-plugins-good/patches/0001-Set-DEFAULT_SSL_STRICT-to-FALSE-by-default.patch create mode 100644 conan/recipes/gstreamer/conandata.yml create mode 100644 conan/recipes/gstreamer/conanfile.py create mode 100644 conan/recipes/libcurl/all/CMakeLists.txt create mode 100644 conan/recipes/libcurl/all/conandata.yml create mode 100644 conan/recipes/libcurl/all/conanfile.py create mode 100644 conan/recipes/libcurl/all/lib_Makefile_add.am create mode 100644 conan/recipes/libcurl/all/patches/001-Update-FindLibSSH2.cmake-add-libssh2-as-possible-nam.patch create mode 100644 conan/recipes/libcurl/all/patches/002-add-missing-file-FindZstd.patch create mode 100644 conan/recipes/libcurl/all/patches/003-Fix-linker-error-of-_getpid-for-QNX.patch create mode 100644 conan/recipes/libcurl/config.yml create mode 100644 conan/recipes/libnghttp2/all/CMakeLists.txt create mode 100644 conan/recipes/libnghttp2/all/conandata.yml create mode 100644 conan/recipes/libnghttp2/all/conanfile.py create mode 100644 conan/recipes/libnghttp2/all/patches/fix-addNghttp2IncludesPathCMake.patch create mode 100644 conan/recipes/libnghttp2/all/patches/fix-findJemalloc.cmake create mode 100644 conan/recipes/libnghttp2/all/patches/fix-findLibevent.cmake create mode 100644 conan/recipes/libnghttp2/all/patches/nghttp_static_include_directories.patch create mode 100644 conan/recipes/libnghttp2/all/patches/nghttp_static_include_directories_1.42.0.patch create mode 100644 conan/recipes/libnghttp2/config.yml create mode 100644 conan/recipes/libsoup/conanfile.py create mode 100644 conan/recipes/poky-sdk/conandata.yml create mode 100644 conan/recipes/poky-sdk/conanfile.py create mode 100644 conan/recipes/pyyaml/conanfile.py create mode 100644 conan/recipes/qnx7-sdp/conanfile.py create mode 100644 conan/recipes/qnx7-sdp/openssl/conanfile.py create mode 100644 conan/recipes/qnx7-sdp/qnx7_toolchain_armv8.cmake create mode 100644 conan/recipes/qnx7-sdp/qnx7_toolchain_x86_64.cmake create mode 100644 conan/recipes/smart-screen-sdk/conanfile.py create mode 100644 conan/recipes/smart-screen-sdk/patches/0001-Smart-Screen-SDK-for-Alexa-Auto-SDK.patch create mode 100644 conan/recipes/smart-screen-sdk/patches/0002-Disable-SmartScreenCapabilityAgents-test.patch rename {builder/meta-aac/recipes-avs/smart-screen-sdk/smart-screen-sdk => conan/recipes/smart-screen-sdk/patches}/0003-Disable-APLClient-dependency.patch (91%) create mode 100644 conan/recipes/smart-screen-sdk/patches/0004-Disable-GUI.patch create mode 100644 conan/recipes/smart-screen-sdk/patches/0005-Template-runtime-version-1.2.patch create mode 100644 conan/recipes/smart-screen-sdk/patches/0006-Ignore-template-runtime-token.patch create mode 100755 conan/setup.py delete mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1addressbook_1_1config_1_1_address_book_configuration-members.html delete mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1addressbook_1_1config_1_1_address_book_configuration.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1alexa_1_1_media_playback_requestor-members.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1alexa_1_1_media_playback_requestor.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1connectivity_1_1_alexa_connectivity-members.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1connectivity_1_1_alexa_connectivity.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1custom_domain_1_1_custom_domain-members.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1custom_domain_1_1_custom_domain.html delete mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller-members.html delete mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1text_to_speech_1_1_text_to_speech-members.html create mode 100644 docs/android/classcom_1_1amazon_1_1aace_1_1text_to_speech_1_1_text_to_speech.html delete mode 100644 docs/android/classcom_1_1amazon_1_1maccandroid_1_1_example_unit_test-members.html delete mode 100644 docs/android/classcom_1_1amazon_1_1maccandroid_1_1_example_unit_test.html delete mode 100644 docs/android/classcom_1_1amazon_1_1maccandroid_1_1_m_a_c_c_android_client-members.html delete mode 100644 docs/android/classcom_1_1amazon_1_1maccandroid_1_1_m_a_c_c_android_client.html delete mode 100644 docs/android/classcom_1_1amazon_1_1maccandroid_1_1model_1_1_player_playback_info-members.html delete mode 100644 docs/android/classcom_1_1amazon_1_1maccandroid_1_1model_1_1_player_playback_info.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1addressbook_1_1_address_book_1_1_address_book_type-members.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1addressbook_1_1_address_book_1_1_address_book_type.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1alexa_1_1_media_playback_requestor_1_1_invocation_reason-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1alexa_1_1_media_playback_requestor_1_1_invocation_reason.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1alexa_1_1_media_playback_requestor_1_1_media_playback_request_status-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1alexa_1_1_media_playback_requestor_1_1_media_playback_request_status.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1audio_1_1_audio_output_1_1_focus_action-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1audio_1_1_audio_output_1_1_focus_action.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1bluetooth_1_1_g_a_t_t_server_1_1_connection_state-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1bluetooth_1_1_g_a_t_t_server_1_1_connection_state.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1connectivity_1_1_alexa_connectivity_1_1_status_code-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1connectivity_1_1_alexa_connectivity_1_1_status_code.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1core_1_1_message_stream_1_1_mode-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1core_1_1_message_stream_1_1_mode.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1custom_domain_1_1_custom_domain_1_1_result_type-members.html create mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1custom_domain_1_1_custom_domain_1_1_result_type.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_call_error-members.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_call_error.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_call_state-members.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_call_state.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_calling_device_configuration_property-members.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_calling_device_configuration_property.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_connection_state-members.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_connection_state.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_d_t_m_f_error-members.html delete mode 100644 docs/android/enumcom_1_1amazon_1_1aace_1_1phonecontrol_1_1_phone_call_controller_1_1_d_t_m_f_error.html create mode 100644 docs/android/search/classes_e.html create mode 100644 docs/android/search/classes_e.js create mode 100644 docs/android/search/functions_12.html create mode 100644 docs/android/search/functions_12.js create mode 100644 docs/cpp/_alexa_connectivity_8h_source.html create mode 100644 docs/cpp/_alexa_connectivity_engine_interface_8h_source.html create mode 100644 docs/cpp/_bluetooth_engine_interfaces_8h_source.html create mode 100644 docs/cpp/_bluetooth_provider_8h_source.html create mode 100644 docs/cpp/_bluetooth_server_socket_8h_source.html create mode 100644 docs/cpp/_bluetooth_socket_8h_source.html create mode 100644 docs/cpp/_byte_array_8h_source.html create mode 100644 docs/cpp/_g_a_t_t_server_8h_source.html create mode 100644 docs/cpp/_media_playback_requestor_8h_source.html create mode 100644 docs/cpp/_message_broker_8h_source.html create mode 100644 docs/cpp/_message_stream_8h_source.html create mode 100644 docs/cpp/_text_to_speech_8h_source.html create mode 100644 docs/cpp/_text_to_speech_engine_interface_8h_source.html create mode 100644 docs/cpp/classaace_1_1address_book_1_1_address_book-members.html create mode 100644 docs/cpp/classaace_1_1address_book_1_1_address_book.html create mode 100644 docs/cpp/classaace_1_1alexa_1_1_external_media_adapter-members.html create mode 100644 docs/cpp/classaace_1_1alexa_1_1_external_media_adapter.html create mode 100644 docs/cpp/classaace_1_1alexa_1_1_media_playback_requestor-members.html create mode 100644 docs/cpp/classaace_1_1alexa_1_1_media_playback_requestor.html create mode 100644 docs/cpp/classaace_1_1alexa_1_1_media_playback_requestor_engine_interface-members.html create mode 100644 docs/cpp/classaace_1_1alexa_1_1_media_playback_requestor_engine_interface.html create mode 100644 docs/cpp/classaace_1_1audio_1_1_audio_input_provider-members.html create mode 100644 docs/cpp/classaace_1_1audio_1_1_audio_input_provider.html create mode 100644 docs/cpp/classaace_1_1audio_1_1_audio_output_provider-members.html create mode 100644 docs/cpp/classaace_1_1audio_1_1_audio_output_provider.html create mode 100644 docs/cpp/classaace_1_1bluetooth_1_1_bluetooth_provider-members.html create mode 100644 docs/cpp/classaace_1_1bluetooth_1_1_bluetooth_provider.html create mode 100644 docs/cpp/classaace_1_1connectivity_1_1_alexa_connectivity-members.html create mode 100644 docs/cpp/classaace_1_1connectivity_1_1_alexa_connectivity.html create mode 100644 docs/cpp/classaace_1_1core_1_1_message_broker-members.html create mode 100644 docs/cpp/classaace_1_1core_1_1_message_broker.html create mode 100644 docs/cpp/classaace_1_1text_to_speech_1_1_text_to_speech-members.html create mode 100644 docs/cpp/classaace_1_1text_to_speech_1_1_text_to_speech.html create mode 100644 docs/cpp/search/classes_d.html create mode 100644 docs/cpp/search/classes_d.js create mode 100644 docs/cpp/search/functions_13.html create mode 100644 docs/cpp/search/functions_13.js create mode 100644 docs/cpp/search/typedefs_c.html create mode 100644 docs/cpp/search/typedefs_c.js create mode 100644 docs/sdk-docs/404.html create mode 100644 docs/sdk-docs/BUILDING/index.html create mode 100644 docs/sdk-docs/CHANGELOG/index.html create mode 100644 docs/sdk-docs/CODE_OF_CONDUCT/index.html create mode 100644 docs/sdk-docs/CONTRIBUTING/index.html create mode 100644 docs/sdk-docs/GETSTARTED/index.html create mode 100644 docs/sdk-docs/LINUX_INTEGRATION/index.html create mode 100644 docs/sdk-docs/MIGRATION/index.html create mode 100644 docs/sdk-docs/MIGRATION_TO_AASB_MESSAGEBROKER/index.html create mode 100644 docs/sdk-docs/NEED_HELP/index.html create mode 100644 docs/sdk-docs/SDK_MODULES/index.html create mode 100644 docs/sdk-docs/SECURITY/index.html create mode 100644 docs/sdk-docs/SEQUENCE_DIAGRAMS/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-apis/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-apl-renderer/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-apps-common-ui/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-apps-common-util/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.png create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.puml create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.png create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.puml create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-carcontrol/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-comms-ui/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-add.png create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-add.puml create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.png create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.puml create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-contacts/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-device-usage/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-lwa-auth/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-media-player/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-navigation/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-settings/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-setup/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-telephony/assets/AACSTelephony_initiateCall.png create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-telephony/assets/AACSTelephony_initiateCall.puml create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-telephony/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-templateruntime-renderer/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-tts/assets/Android_TTS.png create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-tts/assets/Android_TTS.xml create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-tts/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-ux-restrictions/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-voice-interaction/index.html create mode 100644 docs/sdk-docs/aacs/android/app-components/alexa-auto-voice-ui/index.html create mode 100644 docs/sdk-docs/aacs/android/assets/AACSArchDetailed.png create mode 100644 docs/sdk-docs/aacs/android/assets/AACSInit.puml create mode 100644 docs/sdk-docs/aacs/android/assets/AACSInitFlow.png create mode 100644 docs/sdk-docs/aacs/android/assets/AACSWakeword.png create mode 100644 docs/sdk-docs/aacs/android/assets/AACSWakeword.puml create mode 100644 docs/sdk-docs/aacs/android/assets/AACS_CBLLogin.png create mode 100644 docs/sdk-docs/aacs/android/assets/AACS_CBLLogin.puml create mode 100644 docs/sdk-docs/aacs/android/assets/APCP.png create mode 100644 docs/sdk-docs/aacs/android/assets/config.json create mode 100644 docs/sdk-docs/aacs/android/common/commonutils/index.html create mode 100644 docs/sdk-docs/aacs/android/common/ipc/index.html create mode 100644 docs/sdk-docs/aacs/android/index.html create mode 100644 docs/sdk-docs/aacs/android/sample-app/alexa-auto-app/assets/AACSSampleAppArch.png create mode 100644 docs/sdk-docs/aacs/android/sample-app/alexa-auto-app/assets/AACSSampleAppComponentDiagram.drawio create mode 100644 docs/sdk-docs/aacs/android/sample-app/alexa-auto-app/assets/AACSSampleAppComponentDiagram.png create mode 100644 docs/sdk-docs/aacs/android/sample-app/index.html create mode 100644 docs/sdk-docs/aacs/android/service/core-service/src/debug/java/com/amazon/alexaautoclientservice/index.html create mode 100644 docs/sdk-docs/aacs/android/service/index.html create mode 100644 docs/sdk-docs/assets/Migration-ApplicationArch.png create mode 100644 docs/sdk-docs/assets/Migration-Hybrid.png create mode 100644 docs/sdk-docs/assets/Migration-Steps.png create mode 100644 docs/sdk-docs/assets/aac-seq-ttt.plantuml create mode 100644 docs/sdk-docs/assets/aac-seq-ttt.png create mode 100644 docs/sdk-docs/assets/aac-seq-wwe.plantuml create mode 100644 docs/sdk-docs/assets/aac-seq-wwe.png create mode 100644 docs/sdk-docs/assets/aac_linux_integration.png create mode 100644 docs/sdk-docs/assets/images/favicon.png create mode 100644 docs/sdk-docs/assets/javascripts/bundle.a5f8ea78.min.js create mode 100644 docs/sdk-docs/assets/javascripts/bundle.a5f8ea78.min.js.map create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/tinyseg.js create mode 100644 docs/sdk-docs/assets/javascripts/lunr/wordcut.js create mode 100644 docs/sdk-docs/assets/javascripts/workers/search.cefbb252.min.js create mode 100644 docs/sdk-docs/assets/javascripts/workers/search.cefbb252.min.js.map create mode 100644 docs/sdk-docs/assets/number-1.png create mode 100644 docs/sdk-docs/assets/number-2.png create mode 100644 docs/sdk-docs/assets/number-3.png create mode 100644 docs/sdk-docs/assets/number-4.png create mode 100644 docs/sdk-docs/assets/number-5.png create mode 100644 docs/sdk-docs/assets/number-6.png create mode 100644 docs/sdk-docs/assets/stylesheets/main.a617204b.min.css create mode 100644 docs/sdk-docs/assets/stylesheets/main.a617204b.min.css.map create mode 100644 docs/sdk-docs/assets/stylesheets/palette.9204c3b2.min.css create mode 100644 docs/sdk-docs/assets/stylesheets/palette.9204c3b2.min.css.map create mode 100644 docs/sdk-docs/builder/index.html create mode 100644 docs/sdk-docs/index.html create mode 100644 docs/sdk-docs/logo.png create mode 100644 docs/sdk-docs/modules/aasb/aasb-docs/AASB/index.html create mode 100644 docs/sdk-docs/modules/address-book/aasb-docs/AddressBook/index.html create mode 100644 docs/sdk-docs/modules/address-book/assets/remove_contacts.plantuml create mode 100644 docs/sdk-docs/modules/address-book/assets/remove_contacts.png create mode 100644 docs/sdk-docs/modules/address-book/assets/remove_navigation_fav.plantuml create mode 100644 docs/sdk-docs/modules/address-book/assets/remove_navigation_fav.png create mode 100644 docs/sdk-docs/modules/address-book/assets/upload_contacts.plantuml create mode 100644 docs/sdk-docs/modules/address-book/assets/upload_contacts.png create mode 100644 docs/sdk-docs/modules/address-book/assets/upload_navigation_fav.plantuml create mode 100644 docs/sdk-docs/modules/address-book/assets/upload_navigation_fav.png create mode 100644 docs/sdk-docs/modules/address-book/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/Alerts/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/AlexaClient/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/AlexaSpeaker/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/AudioPlayer/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/AuthProvider/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/DeviceSetup/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/DoNotDisturb/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/EqualizerController/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/ExternalMediaAdapter/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/GlobalPreset/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/LocalMediaSource/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/MediaPlaybackRequestor/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/Notifications/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/PlaybackController/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/SpeechRecognizer/index.html create mode 100644 docs/sdk-docs/modules/alexa/aasb-docs/TemplateRuntime/index.html rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/AuthProvider_login.png (100%) rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/AuthProvider_logout.png (100%) create mode 100644 docs/sdk-docs/modules/alexa/assets/DEFAULT_to_DEFAULT_Switching.png create mode 100644 docs/sdk-docs/modules/alexa/assets/Starting_FM_By_Voice.png create mode 100644 docs/sdk-docs/modules/alexa/assets/Switching_Default_With_GUI.png rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/authprovider-cancel-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/authprovider-cancel-sequence.png (100%) rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/authprovider-logout-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/authprovider-logout-sequence.png (100%) rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/authprovider-start-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/alexa/assets/authprovider-start-sequence.png (100%) create mode 100644 docs/sdk-docs/modules/alexa/assets/diagrams/out/complete-interaction-tap-to-talk-sequence.svg create mode 100644 docs/sdk-docs/modules/alexa/assets/diagrams/src/complete-interaction-tap-to-talk-sequence.plantuml create mode 100644 docs/sdk-docs/modules/alexa/index.html create mode 100644 docs/sdk-docs/modules/apl/aasb-docs/APL/index.html create mode 100644 docs/sdk-docs/modules/apl/assets/aac-apl-general-flow.png create mode 100644 docs/sdk-docs/modules/apl/assets/aac-apl-platform-properties.plantuml create mode 100644 docs/sdk-docs/modules/apl/assets/aac-apl-render-document.plantuml create mode 100644 docs/sdk-docs/modules/apl/assets/aac-apl-set-platform-properties.png create mode 100644 docs/sdk-docs/modules/apl/index.html rename {extensions => docs/sdk-docs/modules}/bluetooth/assets/ble.plantuml (100%) rename {extensions => docs/sdk-docs/modules}/bluetooth/assets/ble.png (100%) rename {extensions => docs/sdk-docs/modules}/bluetooth/assets/bluetooth_classic.plantuml (100%) rename {extensions => docs/sdk-docs/modules}/bluetooth/assets/bluetooth_classic.png (100%) create mode 100644 docs/sdk-docs/modules/bluetooth/index.html create mode 100644 docs/sdk-docs/modules/car-control/aasb-docs/CarControl/index.html create mode 100644 docs/sdk-docs/modules/car-control/assets/CarControlConfig.json create mode 100644 docs/sdk-docs/modules/car-control/assets/adjusting_mode_of_a_setting.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/adjusting_mode_of_a_setting.png create mode 100644 docs/sdk-docs/modules/car-control/assets/adjusting_value_of_a_setting.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/adjusting_value_of_a_setting.png create mode 100644 docs/sdk-docs/modules/car-control/assets/assets-1P.json rename {platforms/android => docs/sdk-docs}/modules/car-control/assets/carcontrol_sequence_online.png (100%) create mode 100644 docs/sdk-docs/modules/car-control/assets/setting_mode_of_a_setting.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/setting_mode_of_a_setting.png create mode 100644 docs/sdk-docs/modules/car-control/assets/setting_value_of_a_setting.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/setting_value_of_a_setting.png create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_off_endpoint.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_off_endpoint.png create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_off_toggle_state_of_setting.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_off_toggle_state_of_setting.png create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_on_endpoint.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_on_endpoint.png create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_on_toggle_state_of_setting.plantuml create mode 100644 docs/sdk-docs/modules/car-control/assets/turning_on_toggle_state_of_setting.png create mode 100644 docs/sdk-docs/modules/car-control/index.html create mode 100644 docs/sdk-docs/modules/cbl/aasb-docs/CBL/index.html rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-cancel-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-cancel-sequence.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-logout-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-logout-sequence.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-refresh-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-refresh-sequence.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-start-sequence.plantuml (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl-start-sequence.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl_auth.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl_dereg_inactivity.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl_dereg_user_interaction.png (100%) rename {platforms/android => docs/sdk-docs}/modules/cbl/assets/cbl_refresh.png (100%) create mode 100644 docs/sdk-docs/modules/cbl/index.html create mode 100644 docs/sdk-docs/modules/connectivity/aasb-docs/AlexaConnectivity/index.html create mode 100644 docs/sdk-docs/modules/connectivity/assets/Connectivity-Sequence-CloudAskReport.png create mode 100644 docs/sdk-docs/modules/connectivity/assets/Connectivity-Sequence-CloudAskReport.puml create mode 100644 docs/sdk-docs/modules/connectivity/assets/Connectivity-Sequence-DeviceDiscovery.png create mode 100644 docs/sdk-docs/modules/connectivity/assets/Connectivity-Sequence-DeviceDiscovery.puml create mode 100644 docs/sdk-docs/modules/connectivity/assets/Connectivity-Sequence-sendConnectivityEvent.png create mode 100644 docs/sdk-docs/modules/connectivity/assets/Connectivity-Sequence-sendConnectivityEvent.puml create mode 100644 docs/sdk-docs/modules/connectivity/index.html create mode 100644 docs/sdk-docs/modules/core/AUDIO/index.html create mode 100644 docs/sdk-docs/modules/core/AUTHORIZATION/index.html create mode 100644 docs/sdk-docs/modules/core/RUNTIME_PROPERTIES/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/AudioInput/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/AudioOutput/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/Authorization/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/DeviceUsage/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/LocationProvider/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/NetworkInfoProvider/index.html create mode 100644 docs/sdk-docs/modules/core/aasb-docs/PropertyManager/index.html create mode 100644 docs/sdk-docs/modules/core/index.html create mode 100644 docs/sdk-docs/modules/custom-domain/aasb-docs/CustomDomain/index.html create mode 100644 docs/sdk-docs/modules/custom-domain/assets/custom_context.png create mode 100644 docs/sdk-docs/modules/custom-domain/assets/custom_directives_events.png create mode 100644 docs/sdk-docs/modules/custom-domain/index.html rename {extensions/loopback-detector => docs/sdk-docs/modules/loopback-detector/assets}/loopback-detector-data-flow.png (100%) create mode 100644 docs/sdk-docs/modules/loopback-detector/index.html create mode 100644 docs/sdk-docs/modules/messaging/aasb-docs/Messaging/index.html create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-reading-messages.plantuml create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-reading-messages.png create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-reply-message.plantuml create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-reply-message.png create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-sending-messages.plantuml create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-sending-messages.png create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-connection.plantuml create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-connection.png create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-permissions.plantuml create mode 100644 docs/sdk-docs/modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-permissions.png create mode 100644 docs/sdk-docs/modules/messaging/index.html create mode 100644 docs/sdk-docs/modules/navigation/aasb-docs/Navigation/index.html create mode 100644 docs/sdk-docs/modules/navigation/assets/add_waypoint.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/add_waypoint.png create mode 100644 docs/sdk-docs/modules/navigation/assets/announce_maneuver.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/announce_maneuver.png create mode 100644 docs/sdk-docs/modules/navigation/assets/announce_road_regulation.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/announce_road_regulation.png create mode 100644 docs/sdk-docs/modules/navigation/assets/cancel_navigation.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/cancel_navigation.png create mode 100644 docs/sdk-docs/modules/navigation/assets/map_control.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/map_control.png create mode 100644 docs/sdk-docs/modules/navigation/assets/navigate_previous_waypoint.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/navigate_previous_waypoint.png create mode 100644 docs/sdk-docs/modules/navigation/assets/remove_waypoint.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/remove_waypoint.png create mode 100644 docs/sdk-docs/modules/navigation/assets/show_alternate_routes.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/show_alternate_routes.png create mode 100644 docs/sdk-docs/modules/navigation/assets/show_previous_waypoints.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/show_previous_waypoints.png create mode 100644 docs/sdk-docs/modules/navigation/assets/start_navigation.plantuml create mode 100644 docs/sdk-docs/modules/navigation/assets/start_navigation.png create mode 100644 docs/sdk-docs/modules/navigation/index.html create mode 100644 docs/sdk-docs/modules/phone-control/aasb-docs/PhoneCallController/index.html create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-connection-state-changed.plantuml create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-connection-state-changed.png create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-device-configuration-updated.plantuml create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-device-configuration-updated.png create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-inbound-call.plantuml create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-inbound-call.png create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-outbound-call.plantuml create mode 100644 docs/sdk-docs/modules/phone-control/assets/aac-pcc-outbound-call.png create mode 100644 docs/sdk-docs/modules/phone-control/index.html create mode 100644 docs/sdk-docs/modules/system-audio/index.html create mode 100644 docs/sdk-docs/modules/text-to-speech-provider/index.html create mode 100644 docs/sdk-docs/modules/text-to-speech/aasb-docs/TextToSpeech/index.html create mode 100644 docs/sdk-docs/modules/text-to-speech/assets/GetCapabilities.plantuml create mode 100644 docs/sdk-docs/modules/text-to-speech/assets/GetCapabilities.png create mode 100644 docs/sdk-docs/modules/text-to-speech/assets/PrepareSpeech.plantuml create mode 100644 docs/sdk-docs/modules/text-to-speech/assets/PrepareSpeech.png create mode 100644 docs/sdk-docs/modules/text-to-speech/index.html create mode 100644 docs/sdk-docs/samples/cpp/index.html create mode 100644 docs/sdk-docs/search/search_index.json create mode 100644 docs/sdk-docs/sitemap.xml create mode 100644 docs/sdk-docs/sitemap.xml.gz create mode 100644 extensions/README.md delete mode 100644 extensions/aasb/.gitignore delete mode 100644 extensions/aasb/CMakeLists.txt delete mode 100644 extensions/aasb/README.md delete mode 100644 extensions/aasb/assets/AASBNewArch.png delete mode 100644 extensions/aasb/assets/AASBOldArch.png delete mode 100644 extensions/aasb/docs/AASB/StartServiceMessage.html delete mode 100644 extensions/aasb/docs/AASB/StopServiceMessage.html delete mode 100644 extensions/aasb/docs/APL/ClearAllExecuteCommandsMessage.html delete mode 100644 extensions/aasb/docs/APL/ClearCardMessage.html delete mode 100644 extensions/aasb/docs/APL/ClearDocumentMessage.html delete mode 100644 extensions/aasb/docs/APL/DataSourceUpdateMessage.html delete mode 100644 extensions/aasb/docs/APL/ExecuteCommandsMessage.html delete mode 100644 extensions/aasb/docs/APL/ExecuteCommandsResultMessage.html delete mode 100644 extensions/aasb/docs/APL/InterruptCommandSequenceMessage.html delete mode 100644 extensions/aasb/docs/APL/ProcessActivityEventMessage.html delete mode 100644 extensions/aasb/docs/APL/RenderDocumentMessage.html delete mode 100644 extensions/aasb/docs/APL/RenderDocumentResultMessage.html delete mode 100644 extensions/aasb/docs/APL/SendDataSourceFetchRequestEventMessage.html delete mode 100644 extensions/aasb/docs/APL/SendDeviceWindowStateMessage.html delete mode 100644 extensions/aasb/docs/APL/SendDocumentStateMessage.html delete mode 100644 extensions/aasb/docs/APL/SendRuntimeErrorEventMessage.html delete mode 100644 extensions/aasb/docs/APL/SendUserEventMessage.html delete mode 100644 extensions/aasb/docs/APL/SetAPLMaxVersionMessage.html delete mode 100644 extensions/aasb/docs/APL/SetDocumentIdleTimeoutMessage.html delete mode 100644 extensions/aasb/docs/AddressBook/AddAddressBookMessage.html delete mode 100644 extensions/aasb/docs/AddressBook/AddAddressBookMessageReply.html delete mode 100644 extensions/aasb/docs/AddressBook/RemoveAddressBookMessage.html delete mode 100644 extensions/aasb/docs/AddressBook/RemoveAddressBookMessageReply.html delete mode 100644 extensions/aasb/docs/Alerts/AlertCreatedMessage.html delete mode 100644 extensions/aasb/docs/Alerts/AlertDeletedMessage.html delete mode 100644 extensions/aasb/docs/Alerts/AlertStateChangedMessage.html delete mode 100644 extensions/aasb/docs/Alerts/LocalStopMessage.html delete mode 100644 extensions/aasb/docs/Alerts/RemoveAllAlertsMessage.html delete mode 100644 extensions/aasb/docs/AlexaClient/AuthStateChangedMessage.html delete mode 100644 extensions/aasb/docs/AlexaClient/ConnectionStatusChangedMessage.html delete mode 100644 extensions/aasb/docs/AlexaClient/DialogStateChangedMessage.html delete mode 100644 extensions/aasb/docs/AlexaClient/StopForegroundActivityMessage.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/ConnectivityStateChangeMessage.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/ConnectivityStateChangeMessageReply.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/GetConnectivityStateMessage.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/GetConnectivityStateMessageReply.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/GetIdentifierMessage.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/GetIdentifierMessageReply.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/SendConnectivityEventMessage.html delete mode 100644 extensions/aasb/docs/AlexaConnectivity/SendConnectivityEventMessageReply.html delete mode 100644 extensions/aasb/docs/AlexaSpeaker/LocalAdjustVolumeMessage.html delete mode 100644 extensions/aasb/docs/AlexaSpeaker/LocalSetMuteMessage.html delete mode 100644 extensions/aasb/docs/AlexaSpeaker/LocalSetVolumeMessage.html delete mode 100644 extensions/aasb/docs/AlexaSpeaker/SpeakerSettingsChangedMessage.html delete mode 100644 extensions/aasb/docs/AudioInput/StartAudioInputMessage.html delete mode 100644 extensions/aasb/docs/AudioInput/StopAudioInputMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/GetDurationMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/GetDurationMessageReply.html delete mode 100644 extensions/aasb/docs/AudioOutput/GetNumBytesBufferedMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/GetNumBytesBufferedMessageReply.html delete mode 100644 extensions/aasb/docs/AudioOutput/GetPositionMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/GetPositionMessageReply.html delete mode 100644 extensions/aasb/docs/AudioOutput/MediaErrorMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/MediaStateChangedMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/MutedStateChangedMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/PauseMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/PlayMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/PrepareStreamMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/PrepareURLMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/ResumeMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/SetPositionMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/StopMessage.html delete mode 100644 extensions/aasb/docs/AudioOutput/VolumeChangedMessage.html delete mode 100644 extensions/aasb/docs/AudioPlayer/GetPlayerDurationMessage.html delete mode 100644 extensions/aasb/docs/AudioPlayer/GetPlayerDurationMessageReply.html delete mode 100644 extensions/aasb/docs/AudioPlayer/GetPlayerPositionMessage.html delete mode 100644 extensions/aasb/docs/AudioPlayer/GetPlayerPositionMessageReply.html delete mode 100644 extensions/aasb/docs/AudioPlayer/PlayerActivityChangedMessage.html delete mode 100644 extensions/aasb/docs/AuthProvider/AuthStateChangedMessage.html delete mode 100644 extensions/aasb/docs/AuthProvider/GetAuthStateMessage.html delete mode 100644 extensions/aasb/docs/AuthProvider/GetAuthStateMessageReply.html delete mode 100644 extensions/aasb/docs/AuthProvider/GetAuthTokenMessage.html delete mode 100644 extensions/aasb/docs/AuthProvider/GetAuthTokenMessageReply.html delete mode 100644 extensions/aasb/docs/Authorization/AuthorizationErrorMessage.html delete mode 100644 extensions/aasb/docs/Authorization/AuthorizationStateChangedMessage.html delete mode 100644 extensions/aasb/docs/Authorization/CancelAuthorizationMessage.html delete mode 100644 extensions/aasb/docs/Authorization/EventReceivedMessage.html delete mode 100644 extensions/aasb/docs/Authorization/GetAuthorizationDataMessage.html delete mode 100644 extensions/aasb/docs/Authorization/GetAuthorizationDataMessageReply.html delete mode 100644 extensions/aasb/docs/Authorization/LogoutMessage.html delete mode 100644 extensions/aasb/docs/Authorization/SendEventMessage.html delete mode 100644 extensions/aasb/docs/Authorization/SetAuthorizationDataMessage.html delete mode 100644 extensions/aasb/docs/Authorization/StartAuthorizationMessage.html delete mode 100644 extensions/aasb/docs/CBL/CBLStateChangedMessage.html delete mode 100644 extensions/aasb/docs/CBL/CancelMessage.html delete mode 100644 extensions/aasb/docs/CBL/ClearRefreshTokenMessage.html delete mode 100644 extensions/aasb/docs/CBL/GetRefreshTokenMessage.html delete mode 100644 extensions/aasb/docs/CBL/GetRefreshTokenMessageReply.html delete mode 100644 extensions/aasb/docs/CBL/ResetMessage.html delete mode 100644 extensions/aasb/docs/CBL/SetRefreshTokenMessage.html delete mode 100644 extensions/aasb/docs/CBL/SetUserProfileMessage.html delete mode 100644 extensions/aasb/docs/CBL/StartMessage.html delete mode 100644 extensions/aasb/docs/CarControl/AdjustControllerValueMessageReply.html delete mode 100644 extensions/aasb/docs/CarControl/AdjustModeControllerValueMessage.html delete mode 100644 extensions/aasb/docs/CarControl/AdjustRangeControllerValueMessage.html delete mode 100644 extensions/aasb/docs/CarControl/SetControllerValueMessageReply.html delete mode 100644 extensions/aasb/docs/CarControl/SetModeControllerValueMessage.html delete mode 100644 extensions/aasb/docs/CarControl/SetPowerControllerValueMessage.html delete mode 100644 extensions/aasb/docs/CarControl/SetRangeControllerValueMessage.html delete mode 100644 extensions/aasb/docs/CarControl/SetToggleControllerValueMessage.html delete mode 100644 extensions/aasb/docs/DeviceSetup/SetupCompletedMessage.html delete mode 100644 extensions/aasb/docs/DeviceSetup/SetupCompletedResponseMessage.html delete mode 100644 extensions/aasb/docs/DeviceUsage/ReportNetworkDataUsageMessage.html delete mode 100644 extensions/aasb/docs/DoNotDisturb/DoNotDisturbChangedMessage.html delete mode 100644 extensions/aasb/docs/DoNotDisturb/SetDoNotDisturbMessage.html delete mode 100644 extensions/aasb/docs/EqualizerController/GetBandLevelsMessage.html delete mode 100644 extensions/aasb/docs/EqualizerController/GetBandLevelsMessageReply.html delete mode 100644 extensions/aasb/docs/EqualizerController/LocalAdjustBandLevelsMessage.html delete mode 100644 extensions/aasb/docs/EqualizerController/LocalResetBandsMessage.html delete mode 100644 extensions/aasb/docs/EqualizerController/LocalSetBandLevelsMessage.html delete mode 100644 extensions/aasb/docs/EqualizerController/SetBandLevelsMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/AdjustSeekMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/AuthorizeMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/GetStateMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/LoginCompleteMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/LoginMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/LogoutCompleteMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/LogoutMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/MutedStateChangedMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/PlayControlMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/PlayMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/PlayerErrorMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/PlayerEventMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/RemoveDiscoveredPlayerMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/ReportDiscoveredPlayersMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/RequestTokenMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/SeekMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/SetFocusMessage.html delete mode 100644 extensions/aasb/docs/ExternalMediaAdapter/VolumeChangedMessage.html delete mode 100644 extensions/aasb/docs/GlobalPreset/SetGlobalPresetMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/AdjustSeekMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/GetStateMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/GetStateMessageReply.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/MutedStateChangedMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/PlayControlMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/PlayMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/PlayerErrorMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/PlayerEventMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/SeekMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/SetFocusMessage.html delete mode 100644 extensions/aasb/docs/LocalMediaSource/VolumeChangedMessage.html delete mode 100644 extensions/aasb/docs/LocationProvider/GetCountryMessage.html delete mode 100644 extensions/aasb/docs/LocationProvider/GetCountryMessageReply.html delete mode 100644 extensions/aasb/docs/LocationProvider/GetLocationMessage.html delete mode 100644 extensions/aasb/docs/LocationProvider/GetLocationMessageReply.html delete mode 100644 extensions/aasb/docs/LocationProvider/LocationServiceAccessChangedMessage.html delete mode 100644 extensions/aasb/docs/MainMenu.html delete mode 100644 extensions/aasb/docs/Messaging/ConversationsReportMessage.html delete mode 100644 extensions/aasb/docs/Messaging/SendMessageFailedMessage.html delete mode 100644 extensions/aasb/docs/Messaging/SendMessageMessage.html delete mode 100644 extensions/aasb/docs/Messaging/SendMessageSucceededMessage.html delete mode 100644 extensions/aasb/docs/Messaging/UpdateMessagesStatusFailedMessage.html delete mode 100644 extensions/aasb/docs/Messaging/UpdateMessagesStatusMessage.html delete mode 100644 extensions/aasb/docs/Messaging/UpdateMessagesStatusSucceededMessage.html delete mode 100644 extensions/aasb/docs/Messaging/UpdateMessagingEndpointStateMessage.html delete mode 100644 extensions/aasb/docs/Messaging/UploadConversationsMessage.html delete mode 100644 extensions/aasb/docs/Navigation/AnnounceManeuverMessage.html delete mode 100644 extensions/aasb/docs/Navigation/AnnounceRoadRegulationMessage.html delete mode 100644 extensions/aasb/docs/Navigation/CancelNavigationMessage.html delete mode 100644 extensions/aasb/docs/Navigation/ControlDisplayMessage.html delete mode 100644 extensions/aasb/docs/Navigation/GetNavigationStateMessage.html delete mode 100644 extensions/aasb/docs/Navigation/GetNavigationStateMessageReply.html delete mode 100644 extensions/aasb/docs/Navigation/NavigateToPreviousWaypointMessage.html delete mode 100644 extensions/aasb/docs/Navigation/NavigationErrorMessage.html delete mode 100644 extensions/aasb/docs/Navigation/NavigationEventMessage.html delete mode 100644 extensions/aasb/docs/Navigation/ShowAlternativeRoutesMessage.html delete mode 100644 extensions/aasb/docs/Navigation/ShowAlternativeRoutesSucceededMessage.html delete mode 100644 extensions/aasb/docs/Navigation/ShowPreviousWaypointsMessage.html delete mode 100644 extensions/aasb/docs/Navigation/StartNavigationMessage.html delete mode 100644 extensions/aasb/docs/NetworkInfoProvider/GetNetworkStatusMessage.html delete mode 100644 extensions/aasb/docs/NetworkInfoProvider/GetNetworkStatusMessageReply.html delete mode 100644 extensions/aasb/docs/NetworkInfoProvider/GetWifiSignalStrengthMessage.html delete mode 100644 extensions/aasb/docs/NetworkInfoProvider/GetWifiSignalStrengthMessageReply.html delete mode 100644 extensions/aasb/docs/NetworkInfoProvider/NetworkStatusChangedMessage.html delete mode 100644 extensions/aasb/docs/Notifications/OnNotificationReceivedMessage.html delete mode 100644 extensions/aasb/docs/Notifications/SetIndicatorMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/AnswerMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/CallFailedMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/CallStateChangedMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/CallerIdReceivedMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/ConnectionStateChangedMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/CreateCallIdMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/CreateCallIdMessageReply.html delete mode 100644 extensions/aasb/docs/PhoneCallController/DeviceConfigurationUpdatedMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/DialMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/RedialMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/SendDTMFFailedMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/SendDTMFMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/SendDTMFSucceededMessage.html delete mode 100644 extensions/aasb/docs/PhoneCallController/StopMessage.html delete mode 100644 extensions/aasb/docs/PlaybackController/ButtonPressedMessage.html delete mode 100644 extensions/aasb/docs/PlaybackController/TogglePressedMessage.html delete mode 100644 extensions/aasb/docs/PropertyManager/GetPropertyMessage.html delete mode 100644 extensions/aasb/docs/PropertyManager/GetPropertyMessageReply.html delete mode 100644 extensions/aasb/docs/PropertyManager/PropertyChangedMessage.html delete mode 100644 extensions/aasb/docs/PropertyManager/PropertyStateChangedMessage.html delete mode 100644 extensions/aasb/docs/PropertyManager/SetPropertyMessage.html delete mode 100644 extensions/aasb/docs/Publish Message General Form.html delete mode 100644 extensions/aasb/docs/Reply Message General Form.html delete mode 100644 extensions/aasb/docs/SpeechRecognizer/EndOfSpeechDetectedMessage.html delete mode 100644 extensions/aasb/docs/SpeechRecognizer/StartCaptureMessage.html delete mode 100644 extensions/aasb/docs/SpeechRecognizer/StopCaptureMessage.html delete mode 100644 extensions/aasb/docs/SpeechRecognizer/WakewordDetectedMessage.html delete mode 100644 extensions/aasb/docs/TemplateRuntime/ClearPlayerInfoMessage.html delete mode 100644 extensions/aasb/docs/TemplateRuntime/ClearTemplateMessage.html delete mode 100644 extensions/aasb/docs/TemplateRuntime/DisplayCardClearedMessage.html delete mode 100644 extensions/aasb/docs/TemplateRuntime/RenderPlayerInfoMessage.html delete mode 100644 extensions/aasb/docs/TemplateRuntime/RenderTemplateMessage.html delete mode 100644 extensions/aasb/docs/TextToSpeech/GetCapabilitiesMessage.html delete mode 100644 extensions/aasb/docs/TextToSpeech/GetCapabilitiesMessageReply.html delete mode 100644 extensions/aasb/docs/TextToSpeech/PrepareSpeechCompletedMessage.html delete mode 100644 extensions/aasb/docs/TextToSpeech/PrepareSpeechFailedMessage.html delete mode 100644 extensions/aasb/docs/TextToSpeech/PrepareSpeechMessage.html delete mode 100644 extensions/aasb/meta-aac-aasb/conf/layer.conf delete mode 100644 extensions/aasb/modules/aasb-address-book/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-address-book/aac-aasb-address-book.bb delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/AddAddressBookMessage.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/AddAddressBookMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/AddressBook.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/AddressBookType.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/ContactName.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/NavigationName.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/PhoneData.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/PostalAddress.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/RemoveAddressBookMessage.h delete mode 100644 extensions/aasb/modules/aasb-address-book/engine/include/AASB/Message/AddressBook/AddressBook/RemoveAddressBookMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-alexa/aac-aasb-alexa.bb delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Alerts/AlertCreatedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Alerts/AlertDeletedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Alerts/AlertState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Alerts/AlertStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Alerts/LocalStopMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Alerts/RemoveAllAlertsMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/AuthError.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/AuthState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/AuthStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/ConnectionChangedReason.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/ConnectionStatus.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/ConnectionStatusChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/DialogState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/DialogStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaClient/StopForegroundActivityMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaSpeaker/LocalAdjustVolumeMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaSpeaker/LocalSetMuteMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaSpeaker/LocalSetVolumeMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaSpeaker/SpeakerSettingsChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AlexaSpeaker/SpeakerType.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AudioPlayer/GetPlayerDurationMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AudioPlayer/GetPlayerDurationMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AudioPlayer/GetPlayerPositionMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AudioPlayer/GetPlayerPositionMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AudioPlayer/PlayerActivity.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AudioPlayer/PlayerActivityChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AuthProvider/AuthStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AuthProvider/GetAuthStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AuthProvider/GetAuthStateMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AuthProvider/GetAuthTokenMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/AuthProvider/GetAuthTokenMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/DeviceSetup/SetupCompletedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/DeviceSetup/SetupCompletedResponseMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/DeviceSetup/StatusCode.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/DoNotDisturb/DoNotDisturbChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/DoNotDisturb/SetDoNotDisturbMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/EqualizerBand.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/EqualizerBandLevel.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/GetBandLevelsMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/GetBandLevelsMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/LocalAdjustBandLevelsMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/LocalResetBandsMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/LocalSetBandLevelsMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/EqualizerController/SetBandLevelsMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/AdjustSeekMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/AuthorizeMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/AuthorizedPlayerInfo.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/DiscoveredPlayerInfo.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/ExternalMediaAdapterState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/Favorites.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/GetStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/LoginCompleteMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/LoginMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/LogoutCompleteMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/LogoutMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/MediaType.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/MutedState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/MutedStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/Navigation.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/PlayControlMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/PlayControlType.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/PlayMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/PlaybackStateExternal.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/PlayerErrorMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/PlayerEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/RemoveDiscoveredPlayerMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/ReportDiscoveredPlayersMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/RequestTokenMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/SeekMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/SessionStateExternal.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/SetFocusMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/SupportedPlaybackOperation.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/ValidationMethod.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/ExternalMediaAdapter/VolumeChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/GlobalPreset/SetGlobalPresetMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/AdjustSeekMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/ContentSelector.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/GetStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/GetStateMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/LocalMediaSourceState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/MutedStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/PlayControlMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/PlayMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/PlaybackState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/PlayerErrorMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/PlayerEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/SeekMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/SessionState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/SetFocusMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/Source.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/LocalMediaSource/VolumeChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Notifications/IndicatorState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Notifications/OnNotificationReceivedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/Notifications/SetIndicatorMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/PlaybackController/ButtonPressedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/PlaybackController/PlaybackButton.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/PlaybackController/PlaybackToggle.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/PlaybackController/TogglePressedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/SpeechRecognizer/EndOfSpeechDetectedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/SpeechRecognizer/Initiator.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/SpeechRecognizer/StartCaptureMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/SpeechRecognizer/StopCaptureMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/SpeechRecognizer/WakewordDetectedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/TemplateRuntime/ClearPlayerInfoMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/TemplateRuntime/ClearTemplateMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/TemplateRuntime/DisplayCardClearedMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/TemplateRuntime/FocusState.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/TemplateRuntime/RenderPlayerInfoMessage.h delete mode 100644 extensions/aasb/modules/aasb-alexa/engine/include/AASB/Message/Alexa/TemplateRuntime/RenderTemplateMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-apl/aac-aasb-apl.bb delete mode 100644 extensions/aasb/modules/aasb-apl/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ActivityEvent.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ClearAllExecuteCommandsMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ClearCardMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ClearDocumentMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/DataSourceUpdateMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ExecuteCommandsMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ExecuteCommandsResultMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/InterruptCommandSequenceMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/ProcessActivityEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/RenderDocumentMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/RenderDocumentResultMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SendDataSourceFetchRequestEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SendDeviceWindowStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SendDocumentStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SendRuntimeErrorEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SendUserEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SetAPLMaxVersionMessage.h delete mode 100644 extensions/aasb/modules/aasb-apl/engine/include/AASB/Message/Apl/APL/SetDocumentIdleTimeoutMessage.h delete mode 100644 extensions/aasb/modules/aasb-car-control/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-car-control/aac-aasb-car-control.bb delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/AdjustControllerValueMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/AdjustModeControllerValueMessage.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/AdjustRangeControllerValueMessage.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/SetControllerValueMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/SetModeControllerValueMessage.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/SetPowerControllerValueMessage.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/SetRangeControllerValueMessage.h delete mode 100644 extensions/aasb/modules/aasb-car-control/engine/include/AASB/Message/CarControl/CarControl/SetToggleControllerValueMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-cbl/aac-aasb-cbl.bb delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Engine/CBL/AASBCBLEngineService.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/CBLState.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/CBLStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/CBLStateChangedReason.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/CancelMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/ClearRefreshTokenMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/GetRefreshTokenMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/GetRefreshTokenMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/ResetMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/SetRefreshTokenMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/SetUserProfileMessage.h delete mode 100644 extensions/aasb/modules/aasb-cbl/engine/include/AASB/Message/Cbl/CBL/StartMessage.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-connectivity/aac-aasb-connectivity.bb delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/ConnectivityStateChangeMessage.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/ConnectivityStateChangeMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/GetConnectivityStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/GetConnectivityStateMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/GetIdentifierMessage.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/GetIdentifierMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/SendConnectivityEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/SendConnectivityEventMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-connectivity/engine/include/AASB/Message/Connectivity/AlexaConnectivity/StatusCode.h delete mode 100644 extensions/aasb/modules/aasb-core/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-core/aac-aasb-core.bb delete mode 100644 extensions/aasb/modules/aasb-core/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Engine/Audio/AASBAudioInput.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Engine/Audio/AASBAudioInputProvider.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Engine/Audio/AASBAudioOutput.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Engine/Audio/AASBAudioOutputProvider.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioInput/AudioInputAudioType.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioInput/StartAudioInputMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioInput/StopAudioInputMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/AudioOutputAudioType.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/AudioOutputSourceType.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/AudioStreamEncoding.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/AudioStreamProperty.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/GetDurationMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/GetDurationMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/GetNumBytesBufferedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/GetNumBytesBufferedMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/GetPositionMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/GetPositionMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/MediaError.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/MediaErrorMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/MediaState.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/MediaStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/MutedState.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/MutedStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/PauseMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/PlayMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/PrepareStreamMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/PrepareURLMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/ResumeMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/SetPositionMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/StopMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Audio/AudioOutput/VolumeChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/AuthorizationErrorMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/AuthorizationState.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/AuthorizationStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/CancelAuthorizationMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/EventReceivedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/GetAuthorizationDataMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/GetAuthorizationDataMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/LogoutMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/SendEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/SetAuthorizationDataMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Authorization/Authorization/StartAuthorizationMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/DeviceUsage/DeviceUsage/ReportNetworkDataUsageMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/GetCountryMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/GetCountryMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/GetLocationMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/GetLocationMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/Location.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/LocationServiceAccess.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Location/LocationProvider/LocationServiceAccessChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Network/NetworkInfoProvider/GetNetworkStatusMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Network/NetworkInfoProvider/GetNetworkStatusMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Network/NetworkInfoProvider/GetWifiSignalStrengthMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Network/NetworkInfoProvider/GetWifiSignalStrengthMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Network/NetworkInfoProvider/NetworkStatus.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/Network/NetworkInfoProvider/NetworkStatusChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/PropertyManager/PropertyManager/GetPropertyMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/PropertyManager/PropertyManager/GetPropertyMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/PropertyManager/PropertyManager/PropertyChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/PropertyManager/PropertyManager/PropertyState.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/PropertyManager/PropertyManager/PropertyStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-core/engine/include/AASB/Message/PropertyManager/PropertyManager/SetPropertyMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-messaging/aac-aasb-messaging.bb delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/ConnectionState.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/ConversationsReportMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/ErrorCode.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/PermissionState.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/SendMessageFailedMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/SendMessageMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/SendMessageSucceededMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/UpdateMessagesStatusFailedMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/UpdateMessagesStatusMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/UpdateMessagesStatusSucceededMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/UpdateMessagingEndpointStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-messaging/engine/include/AASB/Message/Messaging/Messaging/UploadConversationsMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-navigation/aac-aasb-navigation.bb delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/AlternateRouteType.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/AnnounceManeuverMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/AnnounceRoadRegulationMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/CancelNavigationMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ControlDisplay.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ControlDisplayMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ErrorCode.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ErrorType.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/EventName.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/GetNavigationStateMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/GetNavigationStateMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/NavigateToPreviousWaypointMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/NavigationErrorMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/NavigationEventMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/RoadRegulation.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ShowAlternativeRoutesMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ShowAlternativeRoutesSucceededMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/ShowPreviousWaypointsMessage.h delete mode 100644 extensions/aasb/modules/aasb-navigation/engine/include/AASB/Message/Navigation/Navigation/StartNavigationMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-phone-control/aac-aasb-phone-control.bb delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/AnswerMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CallError.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CallFailedMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CallState.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CallStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CallerIdReceivedMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CallingDeviceConfigurationProperty.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/ConnectionState.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/ConnectionStateChangedMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CreateCallIdMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/CreateCallIdMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/DTMFError.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/DeviceConfigurationUpdatedMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/DialMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/RedialMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/SendDTMFFailedMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/SendDTMFMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/SendDTMFSucceededMessage.h delete mode 100644 extensions/aasb/modules/aasb-phone-control/engine/include/AASB/Message/PhoneCallController/PhoneCallController/StopMessage.h delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/aac-aasb-text-to-speech.bb delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/include/AASB/Engine/TextToSpeech/AASBTextToSpeech.h delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/include/AASB/Message/TextToSpeech/TextToSpeech/GetCapabilitiesMessage.h delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/include/AASB/Message/TextToSpeech/TextToSpeech/GetCapabilitiesMessageReply.h delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/include/AASB/Message/TextToSpeech/TextToSpeech/PrepareSpeechCompletedMessage.h delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/include/AASB/Message/TextToSpeech/TextToSpeech/PrepareSpeechFailedMessage.h delete mode 100644 extensions/aasb/modules/aasb-text-to-speech/engine/include/AASB/Message/TextToSpeech/TextToSpeech/PrepareSpeechMessage.h delete mode 100644 extensions/aasb/modules/aasb/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb/aac-module-aasb.bb delete mode 100644 extensions/aasb/modules/aasb/engine/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/AASBEngineImpl.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/AASBEngineService.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/AASBHandlerEngineService.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/AASBServiceInterface.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/MessageBroker.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/StreamManager.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB/StreamManagerInterface.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AASB/Message/AASB/StartServiceMessage.h delete mode 100644 extensions/aasb/modules/aasb/engine/include/AASB/Message/AASB/StopServiceMessage.h delete mode 100644 extensions/aasb/modules/aasb/engine/src/AASBEngineService.cpp delete mode 100644 extensions/aasb/modules/aasb/engine/src/AASBHandlerEngineService.cpp delete mode 100644 extensions/aasb/modules/aasb/engine/src/AASBServiceInterface.cpp delete mode 100644 extensions/aasb/modules/aasb/engine/src/MessageBroker.cpp delete mode 100644 extensions/aasb/modules/aasb/engine/src/StreamManager.cpp delete mode 100644 extensions/aasb/modules/aasb/platform/CMakeLists.txt delete mode 100644 extensions/aasb/modules/aasb/platform/include/AACE/AASB/AASBStream.h delete mode 100644 extensions/aasb/modules/aasb/platform/src/AASBStream.cpp delete mode 100644 extensions/aasb/platforms/android/.gitignore delete mode 100644 extensions/aasb/platforms/android/modules/aasb-address-book/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-address-book/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-address-book/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-address-book/src/main/assets/meta-aac/aasb-address-book.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-address-book/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-alexa/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-alexa/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-alexa/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-alexa/src/main/assets/meta-aac/aasb-alexa.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-alexa/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-apl/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-apl/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-apl/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-apl/src/main/assets/meta-aac/aasb-apl.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-apl/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-car-control/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-car-control/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-car-control/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-car-control/src/main/assets/meta-aac/aasb-car-control.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-car-control/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-cbl/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-cbl/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-cbl/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-cbl/src/main/assets/meta-aac/aasb-cbl.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-cbl/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-connectivity/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-connectivity/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-connectivity/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-connectivity/src/main/assets/meta-aac/aasb-connectivity.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-connectivity/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-core/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-core/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-core/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-core/src/main/assets/meta-aac/aasb-core.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-core/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-messaging/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-messaging/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-messaging/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-messaging/src/main/assets/meta-aac/aasb-messaging.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-messaging/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-navigation/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-navigation/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-navigation/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-navigation/src/main/assets/meta-aac/aasb-navigation.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-navigation/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-phone-control/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-phone-control/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-phone-control/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-phone-control/src/main/assets/meta-aac/aasb-phone-control.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-phone-control/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb-text-to-speech/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb-text-to-speech/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb-text-to-speech/src/main/AndroidManifest.xml delete mode 100644 extensions/aasb/platforms/android/modules/aasb-text-to-speech/src/main/assets/meta-aac/aasb-text-to-speech.json delete mode 100644 extensions/aasb/platforms/android/modules/aasb-text-to-speech/src/main/cpp/dummy.cpp delete mode 100644 extensions/aasb/platforms/android/modules/aasb/CMakeLists.txt delete mode 100644 extensions/aasb/platforms/android/modules/aasb/build.gradle delete mode 100644 extensions/aasb/platforms/android/modules/aasb/src/main/assets/meta-aac/aace-aasb.json delete mode 100644 extensions/bluetooth/.gitignore delete mode 100644 extensions/bluetooth/CMakeLists.txt delete mode 100644 extensions/bluetooth/aacs/android/build.gradle delete mode 100644 extensions/bluetooth/aacs/android/modules/aacs-bluetooth/.gitignore delete mode 100644 extensions/bluetooth/aacs/android/modules/aacs-bluetooth/build.gradle delete mode 100644 extensions/bluetooth/aacs/android/modules/aacs-bluetooth/src/main/AndroidManifest.xml delete mode 100644 extensions/bluetooth/aacs/android/modules/aacs-bluetooth/src/main/assets/alexaautoclientservice/aacs-bluetooth.json delete mode 100644 extensions/bluetooth/aacs/android/modules/aacs-bluetooth/src/main/java/com/amazon/alexaautoclientservice/bluetooth/BluetoothModuleFactory.java delete mode 100644 extensions/bluetooth/aacs/android/settings.gradle delete mode 100644 extensions/bluetooth/modules/bluetooth/CMakeLists.txt delete mode 100644 extensions/bluetooth/modules/bluetooth/aac-module-bluetooth.bb delete mode 100644 extensions/bluetooth/modules/bluetooth/engine/CMakeLists.txt delete mode 100644 extensions/bluetooth/modules/bluetooth/platform/CMakeLists.txt delete mode 100644 extensions/bluetooth/platforms/android/.gitignore delete mode 100644 extensions/bluetooth/platforms/android/modules/bluetooth/CMakeLists.txt delete mode 100644 extensions/bluetooth/platforms/android/modules/bluetooth/build.gradle delete mode 100644 extensions/bluetooth/platforms/android/modules/bluetooth/src/main/assets/meta-aac/aace-bluetooth.json delete mode 100644 extensions/bluetooth/samples/android/build.gradle delete mode 100644 extensions/loopback-detector/README.md delete mode 100644 extensions/loopback-detector/extra.conf delete mode 100644 extensions/loopback-detector/modules/loopback-detector/CMakeLists.txt delete mode 100644 extensions/loopback-detector/modules/loopback-detector/aac-module-loopback-detector.bb delete mode 100644 extensions/loopback-detector/platforms/android/.gitignore delete mode 100644 extensions/loopback-detector/platforms/android/modules/loopback-detector/CMakeLists.txt delete mode 100644 extensions/loopback-detector/platforms/android/modules/loopback-detector/build.gradle delete mode 100644 extensions/loopback-detector/platforms/android/modules/loopback-detector/src/main/assets/meta-aac/aace-loopback-detector.json delete mode 100644 extensions/system-audio/README.md delete mode 100644 extensions/system-audio/extra.conf delete mode 100644 extensions/system-audio/modules/system-audio/CMakeLists.txt delete mode 100644 extensions/system-audio/modules/system-audio/aac-module-system-audio.bb delete mode 100644 extensions/system-audio/modules/system-audio/engine/CMakeLists.txt delete mode 100644 extensions/system-audio/modules/system-audio/engine/src/SystemAudioEngine.cpp delete mode 100644 extensions/system-audio/modules/system-audio/engine/test/AudioInputImplTest.cpp delete mode 100644 extensions/system-audio/modules/system-audio/engine/test/AudioOutputImplTest.cpp delete mode 100644 extensions/system-audio/modules/system-audio/engine/test/CMakeLists.txt delete mode 100644 extensions/system-audio/modules/system-audio/engine/test/ThrottleTest.cpp delete mode 100644 extensions/system-audio/modules/system-audio/lib/aal/CMakeLists.txt delete mode 100644 extensions/system-audio/modules/system-audio/lib/aal/src/gstreamer/core.c delete mode 100644 extensions/system-audio/modules/system-audio/lib/aal/src/qsa/core.c create mode 100644 modules/aasb/aasb/messages/aasb.yml rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/aasb/android/src/main/assets/meta-aac/aace-aasb.json rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/cpp/include/AACE/JNI/AASB/AASBBinder.h (100%) rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/cpp/include/AACE/JNI/AASB/AASBStreamBinder.h (100%) rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/cpp/src/AASBBinder.cpp (100%) rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/cpp/src/AASBStreamBinder.cpp (100%) rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/java/com/amazon/aace/aasb/AASB.java (100%) rename {extensions/aasb/platforms/android/modules/aasb => modules/aasb/android}/src/main/java/com/amazon/aace/aasb/AASBStream.java (100%) create mode 100644 modules/aasb/conanfile.py create mode 100644 modules/aasb/engine/include/AACE/Engine/AASB/AASBEngineImpl.h create mode 100644 modules/aasb/engine/include/AACE/Engine/AASB/AASBEngineService.h rename {extensions/aasb/modules => modules}/aasb/engine/src/AASBEngineImpl.cpp (85%) create mode 100644 modules/aasb/engine/src/AASBEngineService.cpp rename {extensions/aasb/modules => modules}/aasb/platform/include/AACE/AASB/AASB.h (100%) rename {extensions/aasb/modules => modules}/aasb/platform/include/AACE/AASB/AASBEngineInterfaces.h (100%) create mode 100644 modules/aasb/platform/include/AACE/AASB/AASBStream.h rename {extensions/aasb/modules => modules}/aasb/platform/src/AASB.cpp (100%) delete mode 100644 modules/address-book/.gitignore delete mode 100644 modules/address-book/CMakeLists.txt delete mode 100644 modules/address-book/aac-module-address-book.bb rename {extensions/aasb/modules/aasb-address-book/engine => modules/address-book/aasb}/include/AASB/Engine/AddressBook/AASBAddressBook.h (82%) rename {extensions/aasb/modules/aasb-address-book/engine => modules/address-book/aasb}/include/AASB/Engine/AddressBook/AASBAddressBookEngineService.h (80%) create mode 100644 modules/address-book/aasb/messages/AddressBook.yml rename {extensions/aasb/modules/aasb-address-book/engine => modules/address-book/aasb}/src/AASBAddressBook.cpp (95%) rename {extensions/aasb/modules/aasb-address-book/engine => modules/address-book/aasb}/src/AASBAddressBookEngineService.cpp (85%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/address-book/android/src/main/assets/meta-aac/aace-addressbook.json rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/cpp/include/AACE/JNI/AddressBook/AddressBookBinder.h (100%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/cpp/include/AACE/JNI/AddressBook/IAddressBookEntriesFactoryBinder.h (100%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/cpp/src/AddressBook/AddressBookBinder.cpp (100%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/cpp/src/AddressBook/AddressBookConfigurationBinder.cpp (100%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/cpp/src/AddressBook/IAddressBookEntriesFactoryBinder.cpp (100%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/java/com/amazon/aace/addressbook/AddressBook.java (92%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/java/com/amazon/aace/addressbook/IAddressBookEntriesFactory.java (100%) rename {platforms/android/modules/addressbook => modules/address-book/android}/src/main/java/com/amazon/aace/addressbook/config/AddressBookConfiguration.java (100%) create mode 100644 modules/address-book/conanfile.py delete mode 100644 modules/address-book/engine/CMakeLists.txt delete mode 100644 modules/address-book/engine/test/CMakeLists.txt delete mode 100644 modules/address-book/platform/CMakeLists.txt rename modules/address-book/{engine/test => testing/unit/tests}/AddressBookCloudUploaderTest.cpp (99%) delete mode 100644 modules/alexa/.gitignore delete mode 100644 modules/alexa/CMakeLists.txt delete mode 100644 modules/alexa/aac-module-alexa.bb rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBAlerts.h (79%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBAlexaClient.h (79%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBAlexaEngineService.h (79%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBAlexaSpeaker.h (78%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBAudioPlayer.h (77%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBAuthProvider.h (79%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBDeviceSetup.h (78%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBDoNotDisturb.h (78%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBEqualizerController.h (80%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBExternalMediaAdapter.h (86%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBGlobalPreset.h (78%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBLocalMediaSource.h (83%) create mode 100644 modules/alexa/aasb/include/AASB/Engine/Alexa/AASBMediaPlaybackRequestor.h rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBNotifications.h (78%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBPlaybackController.h (81%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBSpeechRecognizer.h (78%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBSpeechSynthesizer.h (94%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Engine/Alexa/AASBTemplateRuntime.h (80%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/include/AASB/Message/Alexa/ExternalMediaAdapter/ValidationData.h (100%) create mode 100644 modules/alexa/aasb/messages/Alerts.yml create mode 100644 modules/alexa/aasb/messages/AlexaClient.yml create mode 100644 modules/alexa/aasb/messages/AlexaSpeaker.yml create mode 100644 modules/alexa/aasb/messages/AudioPlayer.yml create mode 100644 modules/alexa/aasb/messages/AuthProvider.yml create mode 100644 modules/alexa/aasb/messages/DeviceSetup.yml create mode 100644 modules/alexa/aasb/messages/DoNotDisturb.yml create mode 100644 modules/alexa/aasb/messages/EqualizerController.yml create mode 100644 modules/alexa/aasb/messages/ExternalMediaAdapter.yml create mode 100644 modules/alexa/aasb/messages/GlobalPreset.yml create mode 100644 modules/alexa/aasb/messages/LocalMediaSource.yml create mode 100644 modules/alexa/aasb/messages/MediaPlaybackRequestor.yml create mode 100644 modules/alexa/aasb/messages/Notifications.yml create mode 100644 modules/alexa/aasb/messages/PlaybackController.yml create mode 100644 modules/alexa/aasb/messages/SpeechRecognizer.yml create mode 100644 modules/alexa/aasb/messages/TemplateRuntime.yml rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBAlerts.cpp (94%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBAlexaClient.cpp (90%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBAlexaEngineService.cpp (91%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBAlexaSpeaker.cpp (95%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBAudioPlayer.cpp (86%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBAuthProvider.cpp (93%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBDeviceSetup.cpp (91%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBDoNotDisturb.cpp (93%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBEqualizerController.cpp (95%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBExternalMediaAdapter.cpp (95%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBGlobalPreset.cpp (92%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBLocalMediaSource.cpp (97%) create mode 100644 modules/alexa/aasb/src/AASBMediaPlaybackRequestor.cpp rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBNotifications.cpp (93%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBPlaybackController.cpp (94%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBSpeechRecognizer.cpp (96%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBSpeechSynthesizer.cpp (100%) rename {extensions/aasb/modules/aasb-alexa/engine => modules/alexa/aasb}/src/AASBTemplateRuntime.cpp (93%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/alexa/android/src/main/assets/meta-aac/aace-alexa.json rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/AlertsBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/AlexaClientBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/AlexaConfigurationBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/AlexaSpeakerBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/AudioPlayerBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/AuthProviderBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/DeviceSetupBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/DoNotDisturbBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/EqualizerControllerBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/ExternalMediaAdapterBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/GlobalPresetBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/LocalMediaSourceBinder.h (100%) create mode 100644 modules/alexa/android/src/main/cpp/include/AACE/JNI/Alexa/MediaPlaybackRequestorBinder.h rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/NotificationsBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/PlaybackControllerBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/SpeechRecognizerBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/SpeechSynthesizerBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/include/AACE/JNI/Alexa/TemplateRuntimeBinder.h (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/AlertsBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/AlexaClientBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/AlexaConfigurationBinder.cpp (94%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/AlexaSpeakerBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/AudioPlayerBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/AuthProviderBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/DeviceSetupBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/DoNotDisturbBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/EqualizerControllerBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/ExternalMediaAdapterBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/GlobalPresetBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/LocalMediaSourceBinder.cpp (100%) create mode 100644 modules/alexa/android/src/main/cpp/src/Alexa/MediaPlaybackRequestorBinder.cpp rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/NotificationsBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/PlaybackControllerBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/SpeechRecognizerBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/SpeechSynthesizerBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/cpp/src/Alexa/TemplateRuntimeBinder.cpp (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/Alerts.java (94%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/AlexaClient.java (97%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/AlexaProperties.java (100%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/AlexaSpeaker.java (94%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/AudioPlayer.java (92%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/AuthProvider.java (95%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/DeviceSetup.java (93%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/DoNotDisturb.java (86%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/EqualizerController.java (95%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/ExternalMediaAdapter.java (98%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/GlobalPreset.java (85%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/LocalMediaSource.java (98%) create mode 100644 modules/alexa/android/src/main/java/com/amazon/aace/alexa/MediaPlaybackRequestor.java rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/Notifications.java (89%) create mode 100644 modules/alexa/android/src/main/java/com/amazon/aace/alexa/PlaybackController.java rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/SpeechRecognizer.java (95%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/SpeechSynthesizer.java (79%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/TemplateRuntime.java (95%) rename {platforms/android/modules/alexa => modules/alexa/android}/src/main/java/com/amazon/aace/alexa/config/AlexaConfiguration.java (88%) create mode 100644 modules/alexa/assets/diagrams/out/complete-interaction-tap-to-talk-sequence.svg create mode 100644 modules/alexa/assets/diagrams/src/complete-interaction-tap-to-talk-sequence.plantuml delete mode 100644 modules/alexa/cmake/FindAVS.cmake create mode 100644 modules/alexa/cmake/aac-alexa-module.cmake create mode 100644 modules/alexa/conanfile.py delete mode 100644 modules/alexa/engine/CMakeLists.txt create mode 100644 modules/alexa/engine/include/AACE/Engine/Alexa/ChannelVolumeManager.h create mode 100644 modules/alexa/engine/include/AACE/Engine/Alexa/DuckingInterface.h create mode 100644 modules/alexa/engine/include/AACE/Engine/Alexa/MediaPlaybackRequestor.h create mode 100644 modules/alexa/engine/include/AACE/Engine/Alexa/MediaPlaybackRequestorEngineImpl.h create mode 100644 modules/alexa/engine/src/ChannelVolumeManager.cpp create mode 100644 modules/alexa/engine/src/MediaPlaybackRequestor.cpp create mode 100644 modules/alexa/engine/src/MediaPlaybackRequestorEngineImpl.cpp delete mode 100644 modules/alexa/engine/test/CMakeLists.txt delete mode 100644 modules/alexa/engine/test/include/AACE/Test/AVS/MockAlexaInterfaceMessageSenderInternalInterface.h delete mode 100644 modules/alexa/engine/test/include/AACE/Test/AVS/MockAttachmentManager.h delete mode 100644 modules/alexa/engine/test/include/AACE/Test/AVS/MockCustomerDataManager.h delete mode 100644 modules/alexa/engine/test/include/AACE/Test/AVS/MockEndpointRegistrationManagerInterface.h delete mode 100644 modules/alexa/engine/test/include/AACE/Test/Alexa/AlexaMockComponentFactory.h delete mode 100644 modules/alexa/engine/test/src/main.cpp create mode 100644 modules/alexa/platform/include/AACE/Alexa/MediaPlaybackRequestor.h create mode 100644 modules/alexa/platform/src/MediaPlaybackRequestor.cpp create mode 100644 modules/alexa/testing/unit/framework/include/AACE/Test/Unit/AVS/MockAlexaInterfaceMessageSenderInternalInterface.h create mode 100644 modules/alexa/testing/unit/framework/include/AACE/Test/Unit/AVS/MockAttachmentManager.h rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockAudioPlayerInterface.h (97%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockAudioPlayerObserverInterface.h (97%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockAuthDelegateInterface.h (86%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockConnectionStatusObserver.h (84%) create mode 100644 modules/alexa/testing/unit/framework/include/AACE/Test/Unit/AVS/MockCustomerDataManager.h rename modules/alexa/{engine/test/include => testing/unit/framework/include/AACE/Test/Unit/AVS}/MockDeviceSettingStorage.h (100%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockDeviceSettingsManager.h (81%) create mode 100644 modules/alexa/testing/unit/framework/include/AACE/Test/Unit/AVS/MockEndpointRegistrationManagerInterface.h rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockInternetConnectionMonitorInterface.h (83%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockMessageObserver.h (82%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockMessageRouter.h (90%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockMessageStorage.h (87%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockMetricRecorder.h (84%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockNotificationsAudioFactoryInterface.h (81%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockRenderPlayerInfoCardsProviderInterface.h (82%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockSpeakerManager.h (100%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockSpeechConfirmationSetting.h (86%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockSpeechEncoder.h (84%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockSystemSoundPlayerInterface.h (80%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockWakeWordConfirmationSetting.h (86%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/AVS/MockWakeWordsSetting.h (86%) create mode 100644 modules/alexa/testing/unit/framework/include/AACE/Test/Unit/Alexa/AlexaMockComponentFactory.h rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/AlexaTestHelper.h (87%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockAlerts.h (87%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockAlexaClient.h (86%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockAudioPlayer.h (82%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockAuthProvider.h (83%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockAuthorizationManager.h (89%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockDeviceSettingsDelegate.h (92%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockDeviceSetup.h (83%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockInitiatorVerifier.h (84%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockNotifications.h (82%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockPlaybackController.h (80%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockSpeechRecognizer.h (83%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockSpeechSynthesizer.h (80%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockTemplateRuntime.h (86%) rename modules/alexa/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Alexa/MockWakewordEngineAdapter.h (87%) rename modules/alexa/{engine/test => testing/unit/framework}/src/AlexaMockComponentFactory.cpp (76%) rename modules/alexa/{engine/test => testing/unit/framework}/src/AlexaTestHelper.cpp (95%) rename modules/alexa/{engine/test => testing/unit/framework}/src/StubMiscStorage.cpp (100%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AlertsEngineImplTest.cpp (98%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AlexaAuthorizationProviderTest.cpp (98%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AlexaClientEngineImplTest.cpp (99%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AlexaConfigurationImplTest.cpp (94%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AlexaEngineClientObserverTest.cpp (100%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AlexaEngineLoggerTest.cpp (95%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AudioPlayerEngineImplTest.cpp (98%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AuthProviderEngineImplTest.cpp (87%) rename modules/alexa/{engine/test/src => testing/unit/tests}/AuthorizationManagerTest.cpp (94%) rename modules/alexa/{engine/test/src => testing/unit/tests}/DeviceSetupEngineImplTest.cpp (89%) rename modules/alexa/{engine/test/src => testing/unit/tests}/DoNotDisturbEngineImplTest.cpp (97%) rename modules/alexa/{engine/test/src => testing/unit/tests}/NotificationsEngineImplTest.cpp (97%) rename modules/alexa/{engine/test/src => testing/unit/tests}/PlaybackControllerEngineImplTest.cpp (98%) rename modules/alexa/{engine/test/src => testing/unit/tests}/SpeechRecognizerEngineImplTest.cpp (80%) rename modules/alexa/{engine/test/src => testing/unit/tests}/SpeechSynthesizerEngineImplTest.cpp (97%) rename modules/alexa/{engine/test/src => testing/unit/tests}/TemplateRuntimeEngineImplTest.cpp (94%) delete mode 100644 modules/apl/CMakeLists.txt delete mode 100644 modules/apl/aac-module-apl.bb rename {extensions/aasb/modules/aasb-apl/engine => modules/apl/aasb}/include/AASB/Engine/APL/AASBAPL.h (75%) rename {extensions/aasb/modules/aasb-apl/engine => modules/apl/aasb}/include/AASB/Engine/APL/AASBAPLEngineService.h (76%) create mode 100644 modules/apl/aasb/messages/APL.yml rename {extensions/aasb/modules/aasb-apl/engine => modules/apl/aasb}/src/AASBAPL.cpp (83%) rename {extensions/aasb/modules/aasb-apl/engine => modules/apl/aasb}/src/AASBAPLEngineService.cpp (85%) rename {platforms/android/modules/apl => modules/apl/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/apl/android/src/main/assets/meta-aac/aace-apl.json rename {platforms/android/modules/apl => modules/apl/android}/src/main/cpp/include/AACE/JNI/APL/APLBinder.h (97%) rename {platforms/android/modules/apl => modules/apl/android}/src/main/cpp/include/AACE/JNI/APL/APLConfigurationBinder.h (100%) rename {platforms/android/modules/apl => modules/apl/android}/src/main/cpp/src/APL/APLBinder.cpp (91%) rename {platforms/android/modules/apl => modules/apl/android}/src/main/cpp/src/APL/APLConfigurationBinder.cpp (100%) rename {platforms/android/modules/apl => modules/apl/android}/src/main/java/com/amazon/aace/apl/APL.java (84%) rename {platforms/android/modules/apl => modules/apl/android}/src/main/java/com/amazon/aace/apl/config/APLConfiguration.java (100%) create mode 100644 modules/apl/assets/aac-apl-general-flow.png create mode 100644 modules/apl/assets/aac-apl-platform-properties.plantuml create mode 100644 modules/apl/assets/aac-apl-render-document.plantuml create mode 100644 modules/apl/assets/aac-apl-set-platform-properties.png create mode 100644 modules/apl/conanfile.py delete mode 100644 modules/apl/engine/CMakeLists.txt create mode 100644 modules/apl/engine/include/AACE/Engine/APL/APLRuntimePropertyGenerator.h create mode 100644 modules/apl/engine/src/APLRuntimePropertyGenerator.cpp delete mode 100644 modules/apl/platform/CMakeLists.txt rename {extensions => modules}/bluetooth/README.md (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/bluetooth/android/src/main/assets/meta-aac/aace-bluetooth.json rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/include/AACE/JNI/Bluetooth/BluetoothProviderBinder.h (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/include/AACE/JNI/Bluetooth/BluetoothServerSocketBinder.h (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/include/AACE/JNI/Bluetooth/BluetoothSocketBinder.h (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/include/AACE/JNI/Bluetooth/GATTServerBinder.h (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/src/Bluetooth/BluetoothProviderBinder.cpp (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/src/Bluetooth/BluetoothServerSocketBinder.cpp (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/src/Bluetooth/BluetoothSocketBinder.cpp (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/cpp/src/Bluetooth/GATTServerBinder.cpp (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/java/com/amazon/aace/bluetooth/BluetoothProvider.java (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/java/com/amazon/aace/bluetooth/BluetoothServerSocket.java (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/java/com/amazon/aace/bluetooth/BluetoothSocket.java (100%) rename {extensions/bluetooth/platforms/android/modules/bluetooth => modules/bluetooth/android}/src/main/java/com/amazon/aace/bluetooth/GATTServer.java (100%) create mode 100644 modules/bluetooth/assets/ble.plantuml create mode 100644 modules/bluetooth/assets/ble.png create mode 100644 modules/bluetooth/assets/bluetooth_classic.plantuml create mode 100644 modules/bluetooth/assets/bluetooth_classic.png create mode 100644 modules/bluetooth/conanfile.py rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/BluetoothEngineService.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/BluetoothServiceInterface.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/GATTCharacteristic.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/GATTDescriptor.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/GATTServerEngineImpl.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/GATTServerInterface.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/include/AACE/Engine/Bluetooth/GATTService.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/src/BluetoothEngineService.cpp (97%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/src/GATTDescriptor.cpp (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/src/GATTServerEngineImpl.cpp (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/engine/src/GATTService.cpp (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/include/AACE/Bluetooth/BluetoothEngineInterfaces.h (96%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/include/AACE/Bluetooth/BluetoothProvider.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/include/AACE/Bluetooth/BluetoothServerSocket.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/include/AACE/Bluetooth/BluetoothSocket.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/include/AACE/Bluetooth/ByteArray.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/include/AACE/Bluetooth/GATTServer.h (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/src/BluetoothProvider.cpp (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/src/ByteArray.cpp (100%) rename {extensions/bluetooth/modules => modules}/bluetooth/platform/src/GATTServer.cpp (100%) rename {extensions => modules}/bluetooth/samples/android/.gitignore (100%) create mode 100644 modules/bluetooth/samples/android/build.gradle rename {platforms/android/app-components/alexa-auto-telephony/aacstelephony => modules/bluetooth/samples/android/modules/sample-bluetooth}/.gitignore (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/build.gradle (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/gradle.properties (100%) rename {samples/android/app => modules/bluetooth/samples/android/modules/sample-bluetooth}/proguard-rules.pro (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/AndroidManifest.xml (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/assets/sample-app/sample-bluetooth.json (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/java/com/amazon/sampleapp/bluetooth/BluetoothModuleFactory.java (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/java/com/amazon/sampleapp/bluetooth/BluetoothProviderHandler.java (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/java/com/amazon/sampleapp/bluetooth/BluetoothServerSocketHandler.java (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/java/com/amazon/sampleapp/bluetooth/BluetoothSocketHandler.java (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/java/com/amazon/sampleapp/bluetooth/GATTServerHandler.java (100%) rename {extensions => modules}/bluetooth/samples/android/modules/sample-bluetooth/src/main/res/values/strings.xml (100%) rename {extensions => modules}/bluetooth/samples/android/settings.gradle (100%) delete mode 100644 modules/car-control/.gitignore delete mode 100644 modules/car-control/CMakeLists.txt delete mode 100644 modules/car-control/aac-module-car-control.bb rename {extensions/aasb/modules/aasb-car-control/engine => modules/car-control/aasb}/include/AASB/Engine/CarControl/AASBCarControl.h (90%) rename {extensions/aasb/modules/aasb-car-control/engine => modules/car-control/aasb}/include/AASB/Engine/CarControl/AASBCarControlEngineService.h (76%) create mode 100644 modules/car-control/aasb/messages/CarControl.yml rename {extensions/aasb/modules/aasb-car-control/engine => modules/car-control/aasb}/src/AASBCarControl.cpp (95%) rename {extensions/aasb/modules/aasb-car-control/engine => modules/car-control/aasb}/src/AASBCarControlEngineService.cpp (84%) rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/car-control/android/src/main/assets/meta-aac/aace-car-control.json rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/cpp/include/AACE/JNI/CarControl/CarControlBinder.h (100%) rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/cpp/src/CarControl/CarControlBinder.cpp (100%) rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/cpp/src/CarControl/CarControlConfigurationBinder.cpp (100%) rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/java/com/amazon/aace/carControl/CarControl.java (97%) rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/java/com/amazon/aace/carControl/CarControlAssets.java (100%) rename {platforms/android/modules/car-control => modules/car-control/android}/src/main/java/com/amazon/aace/carControl/CarControlConfiguration.java (100%) create mode 100644 modules/car-control/assets/adjusting_mode_of_a_setting.plantuml create mode 100644 modules/car-control/assets/adjusting_mode_of_a_setting.png create mode 100644 modules/car-control/assets/adjusting_value_of_a_setting.plantuml create mode 100644 modules/car-control/assets/adjusting_value_of_a_setting.png create mode 100644 modules/car-control/assets/setting_mode_of_a_setting.plantuml create mode 100644 modules/car-control/assets/setting_mode_of_a_setting.png create mode 100644 modules/car-control/assets/setting_value_of_a_setting.plantuml create mode 100644 modules/car-control/assets/setting_value_of_a_setting.png create mode 100644 modules/car-control/assets/turning_off_endpoint.plantuml create mode 100644 modules/car-control/assets/turning_off_endpoint.png create mode 100644 modules/car-control/assets/turning_off_toggle_state_of_setting.plantuml create mode 100644 modules/car-control/assets/turning_off_toggle_state_of_setting.png create mode 100644 modules/car-control/assets/turning_on_endpoint.plantuml create mode 100644 modules/car-control/assets/turning_on_endpoint.png create mode 100644 modules/car-control/assets/turning_on_toggle_state_of_setting.plantuml create mode 100644 modules/car-control/assets/turning_on_toggle_state_of_setting.png create mode 100644 modules/car-control/conanfile.py delete mode 100644 modules/car-control/engine/CMakeLists.txt delete mode 100644 modules/car-control/engine/test/CMakeLists.txt delete mode 100644 modules/car-control/platform/CMakeLists.txt delete mode 100644 modules/cbl/CMakeLists.txt delete mode 100644 modules/cbl/aac-module-cbl.bb rename {extensions/aasb/modules/aasb-cbl/engine => modules/cbl/aasb}/include/AASB/Engine/CBL/AASBCBL.h (79%) create mode 100644 modules/cbl/aasb/include/AASB/Engine/CBL/AASBCBLEngineService.h create mode 100644 modules/cbl/aasb/messages/CBL.yml rename {extensions/aasb/modules/aasb-cbl/engine => modules/cbl/aasb}/src/AASBCBL.cpp (88%) rename {extensions/aasb/modules/aasb-cbl/engine => modules/cbl/aasb}/src/AASBCBLEngineService.cpp (85%) rename {platforms/android/modules/cbl => modules/cbl/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/cbl/android/src/main/assets/meta-aac/aace-cbl.json rename {platforms/android/modules/cbl => modules/cbl/android}/src/main/cpp/include/AACE/JNI/CBL/CBLBinder.h (100%) rename {platforms/android/modules/cbl => modules/cbl/android}/src/main/cpp/src/CBL/CBLBinder.cpp (100%) rename {platforms/android/modules/cbl => modules/cbl/android}/src/main/cpp/src/CBL/CBLConfigurationBinder.cpp (100%) rename {platforms/android/modules/cbl => modules/cbl/android}/src/main/java/com/amazon/aace/cbl/CBL.java (95%) rename {platforms/android/modules/cbl => modules/cbl/android}/src/main/java/com/amazon/aace/cbl/config/CBLConfiguration.java (100%) create mode 100644 modules/cbl/conanfile.py delete mode 100644 modules/cbl/engine/CMakeLists.txt delete mode 100644 modules/cbl/engine/test/CMakeLists.txt delete mode 100644 modules/cbl/platform/CMakeLists.txt rename modules/cbl/{engine/test => testing/unit/tests}/CBLAuthorizationProviderTest.cpp (98%) delete mode 100644 modules/connectivity/CMakeLists.txt delete mode 100644 modules/connectivity/aac-module-connectivity.bb rename {extensions/aasb/modules/aasb-connectivity/engine => modules/connectivity/aasb}/include/AASB/Engine/Connectivity/AASBAlexaConnectivity.h (81%) rename {extensions/aasb/modules/aasb-connectivity/engine => modules/connectivity/aasb}/include/AASB/Engine/Connectivity/AASBConnectivityEngineService.h (80%) create mode 100644 modules/connectivity/aasb/messages/AlexaConnectivity.yml rename {extensions/aasb/modules/aasb-connectivity/engine => modules/connectivity/aasb}/src/AASBAlexaConnectivity.cpp (85%) rename {extensions/aasb/modules/aasb-connectivity/engine => modules/connectivity/aasb}/src/AASBConnectivityEngineService.cpp (80%) rename {platforms/android/modules/connectivity => modules/connectivity/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/connectivity/android/src/main/assets/meta-aac/aace-connectivity.json rename {platforms/android/modules/connectivity => modules/connectivity/android}/src/main/cpp/include/AACE/JNI/Connectivity/AlexaConnectivityBinder.h (100%) rename {platforms/android/modules/connectivity => modules/connectivity/android}/src/main/cpp/src/Connectivity/AlexaConnectivityBinder.cpp (100%) rename {platforms/android/modules/connectivity => modules/connectivity/android}/src/main/java/com/amazon/aace/connectivity/AlexaConnectivity.java (98%) delete mode 100644 modules/connectivity/assets/Connectivity-Sequence-ConnectCloud.png delete mode 100644 modules/connectivity/assets/Connectivity-Sequence-ConnectCloud.puml create mode 100644 modules/connectivity/conanfile.py delete mode 100644 modules/connectivity/engine/CMakeLists.txt delete mode 100644 modules/connectivity/engine/test/CMakeLists.txt delete mode 100644 modules/connectivity/platform/CMakeLists.txt rename modules/connectivity/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Connectivity/MockAlexaConnectivity.h (83%) rename modules/connectivity/{engine/test/src => testing/unit/tests}/AlexaConnectivityEngineImplTest.cpp (97%) create mode 100644 modules/core/AUDIO.md create mode 100644 modules/core/AUTHORIZATION.md delete mode 100644 modules/core/CMakeLists.txt create mode 100644 modules/core/RUNTIME_PROPERTIES.md delete mode 100644 modules/core/aac-module-core.bb rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Audio/AASBAudioEngineService.h (80%) create mode 100644 modules/core/aasb/include/AASB/Engine/Audio/AASBAudioInput.h create mode 100644 modules/core/aasb/include/AASB/Engine/Audio/AASBAudioInputProvider.h create mode 100644 modules/core/aasb/include/AASB/Engine/Audio/AASBAudioOutput.h create mode 100644 modules/core/aasb/include/AASB/Engine/Audio/AASBAudioOutputProvider.h rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Authorization/AASBAuthorization.h (80%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Authorization/AASBAuthorizationEngineService.h (80%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/DeviceUsage/AASBDeviceUsage.h (77%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/DeviceUsage/AASBDeviceUsageEngineService.h (81%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Location/AASBLocationEngineService.h (80%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Location/AASBLocationProvider.h (79%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Network/AASBNetworkEngineService.h (80%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/Network/AASBNetworkInfoProvider.h (78%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/PropertyManager/AASBPropertyManager.h (81%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/include/AASB/Engine/PropertyManager/AASBPropertyManagerEngineService.h (80%) create mode 100644 modules/core/aasb/include/AASB/Utils/StringUtils.h create mode 100644 modules/core/aasb/include/AASB/Utils/UUID.h create mode 100644 modules/core/aasb/messages/AudioInput.yml create mode 100644 modules/core/aasb/messages/AudioOutput.yml create mode 100644 modules/core/aasb/messages/Authorization.yml create mode 100644 modules/core/aasb/messages/DeviceUsage.yml create mode 100644 modules/core/aasb/messages/LocationProvider.yml create mode 100644 modules/core/aasb/messages/NetworkInfoProvider.yml create mode 100644 modules/core/aasb/messages/PropertyManager.yml rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Audio/AASBAudioEngineService.cpp (92%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Audio/AASBAudioInput.cpp (89%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Audio/AASBAudioInputProvider.cpp (87%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Audio/AASBAudioOutput.cpp (79%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Audio/AASBAudioOutputProvider.cpp (87%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Authorization/AASBAuthorization.cpp (84%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Authorization/AASBAuthorizationEngineService.cpp (86%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/DeviceUsage/AASBDeviceUsage.cpp (90%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/DeviceUsage/AASBDeviceUsageEngineService.cpp (85%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Location/AASBLocationEngineService.cpp (85%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Location/AASBLocationProvider.cpp (93%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Network/AASBNetworkEngineService.cpp (85%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/Network/AASBNetworkInfoProvider.cpp (93%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/PropertyManager/AASBPropertyManager.cpp (95%) rename {extensions/aasb/modules/aasb-core/engine => modules/core/aasb}/src/PropertyManager/AASBPropertyManagerEngineService.cpp (86%) rename {platforms/android/modules/core => modules/core/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/core/android/src/main/assets/meta-aac/aace-core.json rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Audio/AudioInputBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Audio/AudioInputProviderBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Audio/AudioOutputBinder.h (84%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Audio/AudioOutputProviderBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Audio/AudioStreamBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Authorization/AuthorizationBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Core/EngineBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Core/EngineConfigurationBinder.h (100%) create mode 100644 modules/core/android/src/main/cpp/include/AACE/JNI/Core/MessageBrokerBinder.h create mode 100644 modules/core/android/src/main/cpp/include/AACE/JNI/Core/MessageStreamBinder.h rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Core/NativeLib.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Core/PlatformInterfaceBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/DeviceUsage/DeviceUsageBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Location/LocationProviderBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Logger/LoggerBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Metrics/MetricsUploaderBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/GlobalRef.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaArray.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaClass.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaEnum.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaField.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaMethod.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaObject.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/JavaString.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/NativeMacros.h (97%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Native/ThreadContext.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Network/NetworkInfoProviderBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/PropertyManager/PropertyManagerBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/include/AACE/JNI/Vehicle/VehicleConfigurationBinder.h (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Audio/AudioInputBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Audio/AudioInputProviderBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Audio/AudioOutputBinder.cpp (84%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Audio/AudioOutputProviderBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Audio/AudioStreamBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Authorization/AuthorizationBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/DeviceUsage/DeviceUsageBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/EngineBinder.cpp (81%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/EngineConfigurationBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Location/LocationProviderBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Logger/LoggerBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Logger/LoggerConfigurationBinder.cpp (100%) create mode 100644 modules/core/android/src/main/cpp/src/MessageBrokerBinder.cpp create mode 100644 modules/core/android/src/main/cpp/src/MessageStreamBinder.cpp rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Metrics/MetricsUploaderBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/JavaArray.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/JavaClass.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/JavaField.cpp (91%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/JavaMethod.cpp (91%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/JavaObject.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/JavaString.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Native/ThreadContext.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Network/NetworkInfoProviderBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/PlatformInterfaceBinder.cpp (86%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/PropertyManager/PropertyManagerBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Storage/StorageConfigurationBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/cpp/src/Vehicle/VehicleConfigurationBinder.cpp (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/audio/AudioFormat.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/audio/AudioInput.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/audio/AudioInputProvider.java (85%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/audio/AudioOutput.java (85%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/audio/AudioOutputProvider.java (86%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/audio/AudioStream.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/authorization/Authorization.java (95%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/CoreProperties.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/Engine.java (86%) create mode 100644 modules/core/android/src/main/java/com/amazon/aace/core/MessageBroker.java create mode 100644 modules/core/android/src/main/java/com/amazon/aace/core/MessageStream.java rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/NativeRef.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/PlatformInterface.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/config/ConfigurationFile.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/config/EngineConfiguration.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/core/config/StreamConfiguration.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/deviceusage/DeviceUsage.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/location/Location.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/location/LocationProvider.java (92%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/logger/Logger.java (92%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/logger/config/LoggerConfiguration.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/network/NetworkInfoProvider.java (91%) create mode 100644 modules/core/android/src/main/java/com/amazon/aace/network/NetworkProperties.java rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/propertymanager/PropertyManager.java (93%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/storage/config/StorageConfiguration.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/vehicle/VehicleProperties.java (100%) rename {platforms/android/modules/core => modules/core/android}/src/main/java/com/amazon/aace/vehicle/config/VehicleConfiguration.java (100%) delete mode 100644 modules/core/assets/PropertyManager_changed.png delete mode 100644 modules/core/assets/PropertyManager_get.png delete mode 100644 modules/core/assets/PropertyManager_set.png create mode 100644 modules/core/assets/diagrams/out/AuthProvider_login.png create mode 100644 modules/core/assets/diagrams/out/AuthProvider_logout.png rename modules/core/assets/{ => diagrams/out}/Authorization_cancel.png (100%) rename modules/core/assets/{ => diagrams/out}/Authorization_logout.png (100%) rename modules/core/assets/{ => diagrams/out}/Authorization_start.png (100%) create mode 100644 modules/core/assets/diagrams/out/authprovider-cancel-sequence.png create mode 100644 modules/core/assets/diagrams/out/authprovider-logout-sequence.png create mode 100644 modules/core/assets/diagrams/out/authprovider-start-sequence.png create mode 100644 modules/core/assets/diagrams/out/ducking.png create mode 100644 modules/core/assets/diagrams/out/ducking_3p_event.png create mode 100644 modules/core/assets/diagrams/src/AudioInput_audio.plantuml create mode 100644 modules/core/assets/diagrams/src/AudioInput_duck.plantuml create mode 100644 modules/core/assets/diagrams/src/AudioOutput_duck3rd.plantuml create mode 100644 modules/core/assets/diagrams/src/AudioOutput_reply.plantuml rename modules/core/assets/{ => diagrams/src}/Authorization_cancel.plantuml (100%) rename modules/core/assets/{ => diagrams/src}/Authorization_logout.plantuml (100%) rename modules/core/assets/{ => diagrams/src}/Authorization_start.plantuml (100%) create mode 100644 modules/core/assets/diagrams/src/authprovider-cancel-sequence.plantuml create mode 100644 modules/core/assets/diagrams/src/authprovider-logout-sequence.plantuml create mode 100644 modules/core/assets/diagrams/src/authprovider-start-sequence.plantuml delete mode 100644 modules/core/cmake/FindSQLite3.cmake create mode 100644 modules/core/cmake/aac-core-module.cmake create mode 100644 modules/core/conanfile.py delete mode 100644 modules/core/engine/CMakeLists.txt create mode 100644 modules/core/engine/include/AACE/Engine/Audio/IStreamAudioStream.h rename {extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB => modules/core/engine/include/AACE/Engine/MessageBroker}/Message.h (89%) create mode 100644 modules/core/engine/include/AACE/Engine/MessageBroker/MessageBrokerEngineService.h create mode 100644 modules/core/engine/include/AACE/Engine/MessageBroker/MessageBrokerImpl.h rename {extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB => modules/core/engine/include/AACE/Engine/MessageBroker}/MessageBrokerInterface.h (88%) create mode 100644 modules/core/engine/include/AACE/Engine/MessageBroker/MessageBrokerServiceInterface.h create mode 100644 modules/core/engine/include/AACE/Engine/MessageBroker/MessageHandlerEngineService.h rename {extensions/aasb/modules/aasb/engine/include/AACE/Engine/AASB => modules/core/engine/include/AACE/Engine/MessageBroker}/PublishMessage.h (89%) create mode 100644 modules/core/engine/include/AACE/Engine/MessageBroker/StreamManagerImpl.h create mode 100644 modules/core/engine/include/AACE/Engine/MessageBroker/StreamManagerInterface.h create mode 100644 modules/core/engine/src/Audio/IStreamAudioStream.cpp rename {extensions/aasb/modules/aasb/engine/src => modules/core/engine/src/MessageBroker}/Message.cpp (96%) create mode 100644 modules/core/engine/src/MessageBroker/MessageBrokerEngineService.cpp create mode 100644 modules/core/engine/src/MessageBroker/MessageBrokerImpl.cpp create mode 100644 modules/core/engine/src/MessageBroker/MessageBrokerServiceInterface.cpp create mode 100644 modules/core/engine/src/MessageBroker/MessageHandlerEngineService.cpp rename {extensions/aasb/modules/aasb/engine/src => modules/core/engine/src/MessageBroker}/PublishMessage.cpp (86%) create mode 100644 modules/core/engine/src/MessageBroker/StreamManagerImpl.cpp delete mode 100644 modules/core/engine/test/CMakeLists.txt delete mode 100644 modules/core/engine/test/include/AACE/Test/Audio/MockAudioInputChannelInterface.h delete mode 100644 modules/core/engine/test/src/main.cpp delete mode 100644 modules/core/platform/CMakeLists.txt create mode 100644 modules/core/platform/include/AACE/Core/MessageBroker.h create mode 100644 modules/core/platform/include/AACE/Core/MessageStream.h create mode 100644 modules/core/testing/unit/framework/include/AACE/Test/Unit/Audio/MockAudioInputChannelInterface.h rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Audio/MockAudioManagerInterface.h (85%) rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Audio/MockAudioOutputChannelInterface.h (82%) rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Authorization/MockAuthorizationProviderListener.h (86%) rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Core/CoreTestHelper.h (86%) rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Core/MockEngineConfiguration.h (82%) rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/Core/MockPlatformInterface.h (81%) rename modules/core/{engine/test/include/AACE/Test => testing/unit/framework/include/AACE/Test/Unit}/PropertyManager/MockPropertyManagerServiceInterface.h (89%) rename modules/core/{engine/test => testing/unit/framework}/src/CoreTestHelper.cpp (88%) rename modules/core/{engine/test/src => testing/unit/tests}/AuthorizationEngineImplTest.cpp (100%) rename modules/core/{engine/test/src => testing/unit/tests}/EngineImplTest.cpp (95%) rename modules/core/{engine/test/src => testing/unit/tests}/LocationProviderEngineImplTest.cpp (100%) create mode 100644 modules/core/testing/unit/tests/ServiceDescriptionTest.cpp rename modules/core/{engine/test/src => testing/unit/tests}/VehicleConfigurationImplTest.cpp (97%) create mode 100644 modules/custom-domain/README.md create mode 100644 modules/custom-domain/aasb/include/AASB/Engine/CustomDomain/AASBCustomDomain.h create mode 100644 modules/custom-domain/aasb/include/AASB/Engine/CustomDomain/AASBCustomDomainEngineService.h create mode 100644 modules/custom-domain/aasb/messages/CustomDomain.yml create mode 100644 modules/custom-domain/aasb/src/AASBCustomDomain.cpp create mode 100644 modules/custom-domain/aasb/src/AASBCustomDomainEngineService.cpp create mode 100644 modules/custom-domain/android/src/main/AndroidManifest.xml create mode 100644 modules/custom-domain/android/src/main/assets/meta-aac/aace-custom-domain.json create mode 100644 modules/custom-domain/android/src/main/cpp/include/AACE/JNI/CustomDomain/CustomDomainBinder.h create mode 100644 modules/custom-domain/android/src/main/cpp/src/CustomDomain/CustomDomainBinder.cpp create mode 100644 modules/custom-domain/android/src/main/java/com/amazon/aace/customDomain/CustomDomain.java create mode 100644 modules/custom-domain/assets/custom_context.png create mode 100644 modules/custom-domain/assets/custom_directives_events.png create mode 100644 modules/custom-domain/conanfile.py create mode 100644 modules/custom-domain/engine/include/AACE/Engine/CustomDomain/CustomDomainCapabilityAgent.h create mode 100644 modules/custom-domain/engine/include/AACE/Engine/CustomDomain/CustomDomainEngineImpl.h create mode 100644 modules/custom-domain/engine/include/AACE/Engine/CustomDomain/CustomDomainEngineService.h create mode 100644 modules/custom-domain/engine/include/AACE/Engine/CustomDomain/CustomDomainHandlerInterface.h create mode 100644 modules/custom-domain/engine/src/CustomDomainCapabilityAgent.cpp create mode 100644 modules/custom-domain/engine/src/CustomDomainEngineImpl.cpp create mode 100644 modules/custom-domain/engine/src/CustomDomainEngineService.cpp create mode 100644 modules/custom-domain/platform/include/AACE/CustomDomain/CustomDomain.h create mode 100644 modules/custom-domain/platform/include/AACE/CustomDomain/CustomDomainEngineInterface.h create mode 100644 modules/custom-domain/platform/src/CustomDomain.cpp create mode 100644 modules/custom-domain/testing/unit/tests/CustomDomainCapabilityAgentTest.cpp create mode 100644 modules/custom-domain/testing/unit/tests/CustomDomainEngineImplTest.cpp rename {extensions => modules}/loopback-detector/LICENSE (100%) rename {extensions => modules}/loopback-detector/NOTICE (100%) create mode 100644 modules/loopback-detector/README.md rename {extensions/loopback-detector/platforms/android/modules/loopback-detector => modules/loopback-detector/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/loopback-detector/android/src/main/assets/meta-aac/aace-loopback-detector.json rename {extensions/loopback-detector/platforms/android/modules/loopback-detector => modules/loopback-detector/android}/src/main/cpp/LoopbackDetectorConfigurationBinder.cpp (100%) create mode 100644 modules/loopback-detector/assets/loopback-detector-data-flow.png create mode 100644 modules/loopback-detector/conanfile.py rename {extensions/loopback-detector/modules => modules}/loopback-detector/engine/CMakeLists.txt (100%) rename {extensions/loopback-detector/modules => modules}/loopback-detector/engine/src/LoopbackDetector.cpp (98%) rename {extensions/loopback-detector/modules => modules}/loopback-detector/engine/src/LoopbackDetector.h (100%) rename {extensions/loopback-detector/modules => modules}/loopback-detector/engine/src/LoopbackDetectorEngineService.cpp (100%) rename {extensions/loopback-detector/modules => modules}/loopback-detector/engine/src/LoopbackDetectorEngineService.h (100%) delete mode 100644 modules/messaging/CMakeLists.txt delete mode 100644 modules/messaging/aac-module-messaging.bb rename {extensions/aasb/modules/aasb-messaging/engine => modules/messaging/aasb}/include/AASB/Engine/Messaging/AASBMessaging.h (82%) rename {extensions/aasb/modules/aasb-messaging/engine => modules/messaging/aasb}/include/AASB/Engine/Messaging/AASBMessagingEngineService.h (80%) create mode 100644 modules/messaging/aasb/messages/Messaging.yml rename {extensions/aasb/modules/aasb-messaging/engine => modules/messaging/aasb}/src/AASBMessaging.cpp (97%) rename {extensions/aasb/modules/aasb-messaging/engine => modules/messaging/aasb}/src/AASBMessagingEngineService.cpp (85%) rename {platforms/android/modules/messaging => modules/messaging/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/messaging/android/src/main/assets/meta-aac/aace-messaging.json rename {platforms/android/modules/messaging => modules/messaging/android}/src/main/cpp/include/AACE/JNI/Messaging/MessagingBinder.h (100%) rename {platforms/android/modules/messaging => modules/messaging/android}/src/main/cpp/src/Messaging/MessagingBinder.cpp (100%) rename {platforms/android/modules/messaging => modules/messaging/android}/src/main/java/com/amazon/aace/messaging/Messaging.java (97%) create mode 100644 modules/messaging/assets/aac-messaging-reading-messages.plantuml create mode 100644 modules/messaging/assets/aac-messaging-reply-message.plantuml create mode 100644 modules/messaging/assets/aac-messaging-sending-messages.plantuml create mode 100644 modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-connection.plantuml create mode 100644 modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-connection.png create mode 100644 modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-permissions.plantuml create mode 100644 modules/messaging/assets/aac-messaging-update-messaging-endpoint-state-permissions.png create mode 100644 modules/messaging/conanfile.py delete mode 100644 modules/messaging/engine/CMakeLists.txt delete mode 100644 modules/messaging/engine/test/CMakeLists.txt delete mode 100644 modules/messaging/platform/CMakeLists.txt rename modules/messaging/{engine/test => testing/unit/tests}/MessagingEngineImplTest.cpp (94%) delete mode 100644 modules/navigation/.gitignore delete mode 100644 modules/navigation/CMakeLists.txt delete mode 100644 modules/navigation/aac-module-navigation.bb rename {extensions/aasb/modules/aasb-navigation/engine => modules/navigation/aasb}/include/AASB/Engine/Navigation/AASBNavigation.h (84%) rename {extensions/aasb/modules/aasb-navigation/engine => modules/navigation/aasb}/include/AASB/Engine/Navigation/AASBNavigationEngineService.h (80%) create mode 100644 modules/navigation/aasb/messages/Navigation.yml rename {extensions/aasb/modules/aasb-navigation/engine => modules/navigation/aasb}/src/AASBNavigation.cpp (97%) rename {extensions/aasb/modules/aasb-navigation/engine => modules/navigation/aasb}/src/AASBNavigationEngineService.cpp (85%) rename {platforms/android/modules/navigation => modules/navigation/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/navigation/android/src/main/assets/meta-aac/aace-navigation.json rename {platforms/android/modules/navigation => modules/navigation/android}/src/main/cpp/include/AACE/JNI/Navigation/NavigationBinder.h (100%) rename {platforms/android/modules/navigation => modules/navigation/android}/src/main/cpp/src/Navigation/NavigationBinder.cpp (100%) rename {platforms/android/modules/navigation => modules/navigation/android}/src/main/cpp/src/Navigation/NavigationConfigurationBinder.cpp (100%) rename {platforms/android/modules/navigation => modules/navigation/android}/src/main/java/com/amazon/aace/navigation/Navigation.java (98%) rename {platforms/android/modules/navigation => modules/navigation/android}/src/main/java/com/amazon/aace/navigation/config/NavigationConfiguration.java (100%) create mode 100644 modules/navigation/conanfile.py delete mode 100644 modules/navigation/engine/CMakeLists.txt delete mode 100644 modules/navigation/engine/test/CMakeLists.txt delete mode 100644 modules/navigation/engine/test/MockAttachmentManager.h delete mode 100644 modules/navigation/platform/CMakeLists.txt rename modules/navigation/{engine/test => testing/unit/tests}/NavigationAssistanceCapabilityAgentTest.cpp (87%) rename modules/navigation/{engine/test => testing/unit/tests}/NavigationCapabilityAgentTest.cpp (95%) rename modules/navigation/{engine/test => testing/unit/tests}/NavigationEngineImplTest.cpp (93%) delete mode 100644 modules/phone-control/.gitignore delete mode 100644 modules/phone-control/CMakeLists.txt delete mode 100644 modules/phone-control/aac-module-phone-control.bb rename {extensions/aasb/modules/aasb-phone-control/engine => modules/phone-control/aasb}/include/AASB/Engine/PhoneCallController/AASBPhoneCallController.h (83%) rename {extensions/aasb/modules/aasb-phone-control/engine => modules/phone-control/aasb}/include/AASB/Engine/PhoneCallController/AASBPhoneCallControllerEngineService.h (84%) create mode 100644 modules/phone-control/aasb/messages/PhoneCallController.yml rename {extensions/aasb/modules/aasb-phone-control/engine => modules/phone-control/aasb}/src/AASBPhoneCallController.cpp (97%) rename {extensions/aasb/modules/aasb-phone-control/engine => modules/phone-control/aasb}/src/AASBPhoneCallControllerEngineService.cpp (86%) rename {platforms/android/modules/phonecontrol => modules/phone-control/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/phone-control/android/src/main/assets/meta-aac/aace-phonecontrol.json rename {platforms/android/modules/phonecontrol => modules/phone-control/android}/src/main/cpp/include/AACE/JNI/PhoneControl/PhoneCallControllerBinder.h (100%) rename {platforms/android/modules/phonecontrol => modules/phone-control/android}/src/main/cpp/src/PhoneControl/PhoneCallControllerBinder.cpp (100%) create mode 100644 modules/phone-control/android/src/main/java/com/amazon/aace/phonecontrol/PhoneCallController.java create mode 100644 modules/phone-control/assets/aac-pcc-connection-state-changed.plantuml create mode 100644 modules/phone-control/assets/aac-pcc-connection-state-changed.png create mode 100644 modules/phone-control/assets/aac-pcc-device-configuration-updated.plantuml create mode 100644 modules/phone-control/assets/aac-pcc-device-configuration-updated.png create mode 100644 modules/phone-control/assets/aac-pcc-inbound-call.plantuml create mode 100644 modules/phone-control/assets/aac-pcc-outbound-call.plantuml create mode 100644 modules/phone-control/conanfile.py delete mode 100644 modules/phone-control/engine/CMakeLists.txt delete mode 100644 modules/phone-control/engine/test/CMakeLists.txt delete mode 100644 modules/phone-control/engine/test/MockAttachmentManager.h delete mode 100644 modules/phone-control/platform/CMakeLists.txt rename modules/phone-control/{engine/test => testing/unit/tests}/PhoneCallControllerCapabilityAgentTest.cpp (95%) rename modules/phone-control/{engine/test => testing/unit/tests}/PhoneCallControllerEngineImplTest.cpp (97%) create mode 100644 modules/system-audio/README.md rename {platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol => modules/system-audio/aal}/.gitignore (100%) create mode 100644 modules/system-audio/aal/CMakeLists.txt rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/README.md (100%) create mode 100644 modules/system-audio/aal/conanfile.py rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/include/aal/aal.h (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/include/aal/common.h (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/.clang-format (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/.github/CONTRIBUTING.md (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/.github/ISSUE_TEMPLATE.md (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/.github/PULL_REQUEST_TEMPLATE.md (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/.gitignore (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/COPYING (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/Makefile (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/README.md (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/ringbuf-test.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/ringbuf.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/lib/c-ringbuf/ringbuf.h (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/common.c (88%) create mode 100644 modules/system-audio/aal/src/gstreamer/core.c rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/gstreamer/core.h (100%) create mode 100644 modules/system-audio/aal/src/gstreamer/mathstubs.c rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/gstreamer/player.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/gstreamer/recorder.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/omxal/core.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/omxal/core.h (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/omxal/player.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/omxal/player.h (100%) create mode 100644 modules/system-audio/aal/src/qsa/core.c rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/qsa/core.h (95%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/qsa/player.c (95%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/qsa/recorder.c (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/test/CMakeLists.txt (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/test/README.md (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/test/player.cpp (100%) rename {extensions/system-audio/modules/system-audio/lib => modules/system-audio}/aal/src/test/recorder.cpp (100%) create mode 100644 modules/system-audio/conanfile.py rename extensions/system-audio/modules/system-audio/assets/config.json.linux => modules/system-audio/configs/linux/config-system-audio.json (100%) rename extensions/system-audio/modules/system-audio/assets/config.json.qnx => modules/system-audio/configs/neutrino/config-system-audio.json (100%) rename {extensions/system-audio/modules => modules}/system-audio/engine/include/AACE/Engine/SystemAudio/AudioInputImpl.h (100%) rename {extensions/system-audio/modules => modules}/system-audio/engine/include/AACE/Engine/SystemAudio/AudioOutputImpl.h (96%) rename {extensions/system-audio/modules => modules}/system-audio/engine/include/AACE/Engine/SystemAudio/SystemAudioEngineService.h (100%) rename {extensions/system-audio/modules => modules}/system-audio/engine/include/AACE/Engine/SystemAudio/Throttle.h (100%) rename {extensions/system-audio/modules => modules}/system-audio/engine/src/AudioInputImpl.cpp (100%) rename {extensions/system-audio/modules => modules}/system-audio/engine/src/AudioOutputImpl.cpp (95%) rename {extensions/system-audio/modules => modules}/system-audio/engine/src/SystemAudioEngineService.cpp (100%) delete mode 100644 modules/text-to-speech-provider/CMakeLists.txt delete mode 100644 modules/text-to-speech-provider/aac-module-text-to-speech-provider.bb rename {platforms/android/modules/text-to-speech-provider => modules/text-to-speech-provider/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/text-to-speech-provider/android/src/main/assets/meta-aac/aace-text-to-speech-provider.json create mode 100644 modules/text-to-speech-provider/conanfile.py delete mode 100644 modules/text-to-speech-provider/engine/CMakeLists.txt delete mode 100644 modules/text-to-speech/.gitignore delete mode 100644 modules/text-to-speech/CMakeLists.txt delete mode 100644 modules/text-to-speech/aac-module-text-to-speech.bb create mode 100644 modules/text-to-speech/aasb/include/AASB/Engine/TextToSpeech/AASBTextToSpeech.h rename {extensions/aasb/modules/aasb-text-to-speech/engine => modules/text-to-speech/aasb}/include/AASB/Engine/TextToSpeech/AASBTextToSpeechEngineService.h (81%) create mode 100644 modules/text-to-speech/aasb/messages/TextToSpeech.yml rename {extensions/aasb/modules/aasb-text-to-speech/engine => modules/text-to-speech/aasb}/src/AASBTextToSpeech.cpp (90%) rename {extensions/aasb/modules/aasb-text-to-speech/engine => modules/text-to-speech/aasb}/src/AASBTextToSpeechEngineService.cpp (86%) rename {platforms/android/modules/text-to-speech => modules/text-to-speech/android}/src/main/AndroidManifest.xml (100%) create mode 100644 modules/text-to-speech/android/src/main/assets/meta-aac/aace-text-to-speech.json rename {platforms/android/modules/text-to-speech => modules/text-to-speech/android}/src/main/cpp/include/AACE/JNI/TextToSpeech/TextToSpeechBinder.h (100%) rename {platforms/android/modules/text-to-speech => modules/text-to-speech/android}/src/main/cpp/src/TextToSpeech/TextToSpeechBinder.cpp (100%) rename {platforms/android/modules/text-to-speech => modules/text-to-speech/android}/src/main/java/com/amazon/aace/textToSpeech/TextToSpeech.java (95%) delete mode 100644 modules/text-to-speech/assets/CapabilitiesReceived.plantuml delete mode 100644 modules/text-to-speech/assets/CapabilitiesReceived.png delete mode 100644 modules/text-to-speech/assets/PrepareSpeechCompleted.plantuml delete mode 100644 modules/text-to-speech/assets/PrepareSpeechCompleted.png delete mode 100644 modules/text-to-speech/assets/PrepareSpeechFailed.plantuml delete mode 100644 modules/text-to-speech/assets/PrepareSpeechFailed.png create mode 100644 modules/text-to-speech/conanfile.py delete mode 100644 modules/text-to-speech/engine/CMakeLists.txt delete mode 100644 modules/text-to-speech/engine/test/CMakeLists.txt delete mode 100644 modules/text-to-speech/platform/CMakeLists.txt rename modules/text-to-speech/{engine/test => testing/unit/tests}/TextToSpeechEngineImplTest.cpp (96%) delete mode 100644 platforms/android/.gitignore delete mode 100644 platforms/android/alexa-auto-client-service/README.md delete mode 100755 platforms/android/alexa-auto-client-service/android-service/.gitignore delete mode 100644 platforms/android/alexa-auto-client-service/android-service/README.md delete mode 100755 platforms/android/alexa-auto-client-service/android-service/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/androidTest/assets/file-util-res/aacs_config.json delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/AndroidManifest.xml delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/ComponentRegistry.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/mediaPlayer/exo/MediaSourceFactory.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/mediaPlayer/exo/PlaylistParser.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/mediaPlayer/raw/RawAudioOutputHandler.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/modules/mediaManager/LocalMediaSourceHandler.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/modules/propertyManager/PropertyManagerHandler.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/receiver/SystemPropertyChangeReceiver.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/util/FileUtil.java delete mode 100644 platforms/android/alexa-auto-client-service/android-service/service/src/main/java/com/amazon/alexaautoclientservice/util/MediaPlayerUtil.java delete mode 100755 platforms/android/alexa-auto-client-service/android-service/settings.gradle delete mode 100644 platforms/android/alexa-auto-client-service/assets/AACS_CBLLogin.png delete mode 100644 platforms/android/alexa-auto-client-service/assets/AACS_CBLLogin.puml delete mode 100644 platforms/android/alexa-auto-client-service/assets/config.json delete mode 100644 platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessages.java delete mode 100644 platforms/android/alexa-auto-client-service/commonutils/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/commonutils/settings.gradle delete mode 100644 platforms/android/alexa-auto-client-service/constants/aacsconstants/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/constants/build.gradle delete mode 100644 platforms/android/alexa-auto-client-service/ipc/.gitignore delete mode 100644 platforms/android/alexa-auto-client-service/ipc/README.md delete mode 100644 platforms/android/alexa-auto-client-service/ipc/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-apis/README.md delete mode 100644 platforms/android/app-components/alexa-auto-apis/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/README.md delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/AndroidManifest.xml delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/assets/APLViewport.json delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLActivity.java delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/Constants.java delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/handler/APLHandler.java delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLReceiver.java delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/res/layout/activity_apl.xml delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/main/res/layout/apl_view.xml delete mode 100644 platforms/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/handler/APLHandlerTest.java delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-ui/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/amazon_alexa_placeholder_logo.png delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-util/README.md delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-util/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-util/src/main/AndroidManifest.xml delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/Constants.java delete mode 100644 platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/FileUtil.java delete mode 100644 platforms/android/app-components/alexa-auto-carcontrol/README.md delete mode 100644 platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-carcontrol/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-carcontrol/settings.gradle delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/README.md delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/AndroidManifest.xml delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/Constants.java delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/ContactsControllerImpl.java delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceRepository.java delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationModule.java delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiver.java delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout-land/communication_setup_fragment.xml delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_setup_fragment.xml delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/res/values-land/dimens.xml delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/res/values/dimens.xml delete mode 100644 platforms/android/app-components/alexa-auto-comms-ui/src/main/res/values/strings.xml delete mode 100644 platforms/android/app-components/alexa-auto-contacts/README.md delete mode 100644 platforms/android/app-components/alexa-auto-contacts/aacscontacts/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-contacts/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-contacts/settings.gradle delete mode 100644 platforms/android/app-components/alexa-auto-device-usage/README.md delete mode 100644 platforms/android/app-components/alexa-auto-lwa-auth/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-lwa-auth/src/main/AndroidManifest.xml delete mode 100644 platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AuthReceiver.java delete mode 100644 platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/CBLReceiver.java delete mode 100644 platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthController.java delete mode 100644 platforms/android/app-components/alexa-auto-media-player/README.md delete mode 100644 platforms/android/app-components/alexa-auto-media-player/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-media-player/src/main/AndroidManifest.xml delete mode 100644 platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/AudioPlayerHandler.java delete mode 100644 platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaSourceFactory.java delete mode 100644 platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaSessionManager.java delete mode 100644 platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackController.java delete mode 100644 platforms/android/app-components/alexa-auto-navigation/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-navigation/src/main/res/values/dimens.xml delete mode 100644 platforms/android/app-components/alexa-auto-settings/README.md delete mode 100644 platforms/android/app-components/alexa-auto-settings/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-settings/src/main/AndroidManifest.xml delete mode 100644 platforms/android/app-components/alexa-auto-settings/src/main/assets/locales.json delete mode 100644 platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSettingsLanguagesFragment.java delete mode 100644 platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/PreferenceKeys.java delete mode 100644 platforms/android/app-components/alexa-auto-settings/src/main/res/layout/settings_alexa_language_layout.xml delete mode 100644 platforms/android/app-components/alexa-auto-settings/src/main/res/values/strings.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/README.md delete mode 100644 platforms/android/app-components/alexa-auto-setup/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/SetupComponent.java delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/receiver/NetworkStateChangeReceiver.java delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragment.java delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/auth_provider_login_finished.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_error.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_finished.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/enable_preview_mode.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/location_consent.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_display_cbl_code.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_start.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/network_fragment.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/setup_not_complete.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/start_language_selection.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/auth_provider_login_finished.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_error.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_finished.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/enable_preview_mode.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/location_consent.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/login_display_cbl_code.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/login_start.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/network_fragment.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/setup_not_complete.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/layout/start_language_selection.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/values-land/dimens.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/values/dimens.xml delete mode 100644 platforms/android/app-components/alexa-auto-setup/src/main/res/values/strings.xml delete mode 100644 platforms/android/app-components/alexa-auto-telephony/README.md delete mode 100644 platforms/android/app-components/alexa-auto-telephony/aacstelephony/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-telephony/aacstelephony/consumer-rules.pro delete mode 100644 platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/PhoneCallController.java delete mode 100644 platforms/android/app-components/alexa-auto-telephony/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-telephony/settings.gradle delete mode 100644 platforms/android/app-components/alexa-auto-templateruntime-renderer/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather.xml delete mode 100644 platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/dimens.xml delete mode 100644 platforms/android/app-components/alexa-auto-tts/README.md delete mode 100644 platforms/android/app-components/alexa-auto-tts/aacstts/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-tts/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-tts/gradle.properties delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/README.md delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/build.gradle delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/earcon/EarconController.java delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiver.java delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSession.java delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values/styles.xml delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiverTest.java delete mode 100644 platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSessionTest.java delete mode 100644 platforms/android/modules/abifilter.gradle delete mode 100644 platforms/android/modules/addressbook/CMakeLists.txt delete mode 100644 platforms/android/modules/addressbook/README.md delete mode 100644 platforms/android/modules/addressbook/assets/remove_contacts.plantuml delete mode 100644 platforms/android/modules/addressbook/assets/remove_contacts.png delete mode 100644 platforms/android/modules/addressbook/assets/remove_navigation_fav.plantuml delete mode 100644 platforms/android/modules/addressbook/assets/remove_navigation_fav.png delete mode 100644 platforms/android/modules/addressbook/assets/upload_contacts.plantuml delete mode 100644 platforms/android/modules/addressbook/assets/upload_contacts.png delete mode 100644 platforms/android/modules/addressbook/assets/upload_navigation_fav.plantuml delete mode 100644 platforms/android/modules/addressbook/assets/upload_navigation_fav.png delete mode 100644 platforms/android/modules/addressbook/build.gradle delete mode 100644 platforms/android/modules/addressbook/src/main/assets/meta-aac/aace-addressbook.json delete mode 100644 platforms/android/modules/alexa/CMakeLists.txt delete mode 100644 platforms/android/modules/alexa/README.md delete mode 100644 platforms/android/modules/alexa/build.gradle delete mode 100644 platforms/android/modules/alexa/src/main/assets/meta-aac/aace-alexa.json delete mode 100644 platforms/android/modules/alexa/src/main/java/com/amazon/aace/alexa/PlaybackController.java delete mode 100644 platforms/android/modules/apl-render/README.md delete mode 100644 platforms/android/modules/apl-render/build.gradle delete mode 100644 platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLPresenter.java delete mode 100644 platforms/android/modules/apl-render/src/main/libs/.gitignore delete mode 100644 platforms/android/modules/apl/CMakeLists.txt delete mode 100644 platforms/android/modules/apl/README.md delete mode 100644 platforms/android/modules/apl/build.gradle delete mode 100644 platforms/android/modules/apl/src/main/assets/meta-aac/aace-apl.json delete mode 100644 platforms/android/modules/car-control/CMakeLists.txt delete mode 100644 platforms/android/modules/car-control/README.md delete mode 100644 platforms/android/modules/car-control/assets/meta-aac/aace-car-control.json delete mode 100644 platforms/android/modules/car-control/build.gradle delete mode 100644 platforms/android/modules/car-control/src/main/assets/meta-aac/aace-car-control.json delete mode 100644 platforms/android/modules/cbl/CMakeLists.txt delete mode 100644 platforms/android/modules/cbl/README.md delete mode 100644 platforms/android/modules/cbl/build.gradle delete mode 100644 platforms/android/modules/cbl/src/main/assets/meta-aac/aace-cbl.json delete mode 100644 platforms/android/modules/connectivity/CMakeLists.txt delete mode 100644 platforms/android/modules/connectivity/README.md delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-CloudAskReport.png delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-CloudAskReport.puml delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-ConnectCloud.png delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-ConnectCloud.puml delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-DeviceDiscovery.png delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-DeviceDiscovery.puml delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-sendConnectivityEvent.png delete mode 100644 platforms/android/modules/connectivity/assets/Connectivity-Sequence-sendConnectivityEvent.puml delete mode 100644 platforms/android/modules/connectivity/build.gradle delete mode 100644 platforms/android/modules/connectivity/src/main/assets/meta-aac/aace-connectivity.json delete mode 100644 platforms/android/modules/core/CMakeLists.txt delete mode 100644 platforms/android/modules/core/README.md delete mode 100644 platforms/android/modules/core/assets/Authorization_cancel.plantuml delete mode 100644 platforms/android/modules/core/assets/Authorization_cancel.png delete mode 100644 platforms/android/modules/core/assets/Authorization_logout.plantuml delete mode 100644 platforms/android/modules/core/assets/Authorization_logout.png delete mode 100644 platforms/android/modules/core/assets/Authorization_start.plantuml delete mode 100644 platforms/android/modules/core/assets/Authorization_start.png delete mode 100644 platforms/android/modules/core/assets/PropertyManager_changed.png delete mode 100644 platforms/android/modules/core/assets/PropertyManager_get.png delete mode 100644 platforms/android/modules/core/assets/PropertyManager_set.png delete mode 100644 platforms/android/modules/core/build.gradle delete mode 100644 platforms/android/modules/core/src/main/assets/meta-aac/aace-core.json delete mode 100644 platforms/android/modules/core/src/main/java/com/amazon/aace/network/NetworkProperties.java delete mode 100644 platforms/android/modules/gradle.properties delete mode 100644 platforms/android/modules/maccandroid/.classpath delete mode 100644 platforms/android/modules/maccandroid/build.gradle delete mode 100644 platforms/android/modules/messaging/CMakeLists.txt delete mode 100644 platforms/android/modules/messaging/README.md delete mode 100644 platforms/android/modules/messaging/assets/aac-messaging-reading-messages.png delete mode 100644 platforms/android/modules/messaging/assets/aac-messaging-reply-message.png delete mode 100644 platforms/android/modules/messaging/assets/aac-messaging-sending-messages.png delete mode 100644 platforms/android/modules/messaging/build.gradle delete mode 100644 platforms/android/modules/messaging/src/main/assets/meta-aac/aace-messaging.json delete mode 100644 platforms/android/modules/navigation/CMakeLists.txt delete mode 100644 platforms/android/modules/navigation/README.md delete mode 100644 platforms/android/modules/navigation/assets/add_waypoint.png delete mode 100644 platforms/android/modules/navigation/assets/announce_maneuver.png delete mode 100644 platforms/android/modules/navigation/assets/announce_road_regulation.png delete mode 100644 platforms/android/modules/navigation/assets/cancel_navigation.png delete mode 100644 platforms/android/modules/navigation/assets/map_control.png delete mode 100644 platforms/android/modules/navigation/assets/navigate_previous_waypoint.png delete mode 100644 platforms/android/modules/navigation/assets/remove_waypoint.png delete mode 100644 platforms/android/modules/navigation/assets/show_alternate_routes.png delete mode 100644 platforms/android/modules/navigation/assets/show_previous_waypoint.png delete mode 100644 platforms/android/modules/navigation/assets/start_navigation.png delete mode 100644 platforms/android/modules/navigation/build.gradle delete mode 100644 platforms/android/modules/navigation/src/main/assets/meta-aac/aace-navigation.json delete mode 100644 platforms/android/modules/phonecontrol/CMakeLists.txt delete mode 100644 platforms/android/modules/phonecontrol/README.md delete mode 100644 platforms/android/modules/phonecontrol/build.gradle delete mode 100644 platforms/android/modules/phonecontrol/src/main/assets/meta-aac/aace-phonecontrol.json delete mode 100644 platforms/android/modules/phonecontrol/src/main/java/com/amazon/aace/phonecontrol/PhoneCallController.java delete mode 100644 platforms/android/modules/settings.gradle delete mode 100644 platforms/android/modules/text-to-speech-provider/README.md delete mode 100644 platforms/android/modules/text-to-speech-provider/build.gradle delete mode 100644 platforms/android/modules/text-to-speech-provider/src/main/assets/meta-aac/aace-text-to-speech-provider.json delete mode 100644 platforms/android/modules/text-to-speech/CMakeLists.txt delete mode 100644 platforms/android/modules/text-to-speech/README.md delete mode 100644 platforms/android/modules/text-to-speech/assets/CapabilitiesReceived.plantuml delete mode 100644 platforms/android/modules/text-to-speech/assets/CapabilitiesReceived.png delete mode 100644 platforms/android/modules/text-to-speech/assets/GetCapabilities.plantuml delete mode 100644 platforms/android/modules/text-to-speech/assets/GetCapabilities.png delete mode 100644 platforms/android/modules/text-to-speech/assets/PrepareSpeech.plantuml delete mode 100644 platforms/android/modules/text-to-speech/assets/PrepareSpeech.png delete mode 100644 platforms/android/modules/text-to-speech/assets/PrepareSpeechCompleted.plantuml delete mode 100644 platforms/android/modules/text-to-speech/assets/PrepareSpeechCompleted.png delete mode 100644 platforms/android/modules/text-to-speech/assets/PrepareSpeechFailed.plantuml delete mode 100644 platforms/android/modules/text-to-speech/assets/PrepareSpeechFailed.png delete mode 100644 platforms/android/modules/text-to-speech/build.gradle delete mode 100644 platforms/android/modules/text-to-speech/src/main/assets/meta-aac/aace-text-to-speech.json delete mode 100644 samples/android-aacs-sample-app/alexa-auto-app/README.md delete mode 100644 samples/android-aacs-sample-app/alexa-auto-app/build.gradle delete mode 100755 samples/android-aacs-sample-app/alexa-auto-app/gradle.properties delete mode 100644 samples/android-aacs-sample-app/alexa-auto-app/src/main/AndroidManifest.xml delete mode 100644 samples/android-aacs-sample-app/alexa-auto-app/src/main/assets/config/aacs_config.json delete mode 100644 samples/android-aacs-sample-app/build.gradle delete mode 100644 samples/android-aacs-sample-app/settings.gradle delete mode 100644 samples/android/.gitignore delete mode 100644 samples/android/README.md delete mode 100644 samples/android/app/.gitignore delete mode 100644 samples/android/app/build.gradle delete mode 100644 samples/android/app/src/androidTest/java/com/amazon/sampleapp/ExampleInstrumentedTest.java delete mode 100644 samples/android/app/src/main/AndroidManifest.xml delete mode 100644 samples/android/app/src/main/aidl/com/amazon/alexalve/ILVCClient.aidl delete mode 100644 samples/android/app/src/main/aidl/com/amazon/alexalve/ILVCService.aidl delete mode 100644 samples/android/app/src/main/assets/CarControlAssets.json delete mode 100644 samples/android/app/src/main/assets/Contacts.json delete mode 100644 samples/android/app/src/main/assets/ConversationsReport.json delete mode 100644 samples/android/app/src/main/assets/NavigationFavorites.json delete mode 100644 samples/android/app/src/main/assets/NavigationState.json delete mode 100644 samples/android/app/src/main/assets/app_config.json delete mode 100644 samples/android/app/src/main/assets/models/.gitkeep delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/FileUtils.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/LVCInteractionService.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/LimitedSizeArrayList.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/MainActivity.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/NetworkStatsManagerRunner.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/SampleApplication.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/AddressBook/AddressBookHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Alerts/AlertsHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/AlexaClient/AlexaClientHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/AlexaSpeaker/AlexaSpeakerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/AudioFocusController.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/AudioInputHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/AudioInputProviderHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/AudioOutputHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/AudioOutputProviderHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/MediaSourceFactory.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/PlaylistParser.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/RawAudioOutputHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/Releasable.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Audio/UnifiedAudioOutput.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/AudioPlayer/AudioPlayerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Authorization/AuthorizationHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Authorization/CBLAuthorizationHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/CarControl/BoolController.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/CarControl/CarControlDataProvider.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/CarControl/CarControlHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/CarControl/ModeController.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/CarControl/RangeController.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/DeviceSetup/DeviceSetupHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/DeviceUsage/DeviceUsageHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/DoNotDisturb/DoNotDisturbHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/EqualizerController/EQUtils.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/EqualizerController/EqualizerConfiguration.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/EqualizerController/EqualizerControllerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/ExternalMediaPlayer/MACCPlayer.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/AMLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/BluetoothLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/CDLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/DABLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/DefaultMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/FMLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/LineInLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/LocalMediaSourceHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/SatelliteLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/SiriusXMLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocalMediaSource/USBLocalMediaSource.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/LocationProvider/LocationProviderHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Logger/LoggerFragment.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Logger/LoggerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Messaging/MessagingHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Navigation/NavigationHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/NetworkInfoProvider/NetworkConnectionObserver.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/NetworkInfoProvider/NetworkInfoProviderHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/Notifications/NotificationsHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/PhoneCallController/PhoneCallControllerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/PlaybackController/PlaybackControllerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/PropertyManager/PropertyManagerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/SpeechRecognizer/SpeechRecognizerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/SpeechSynthesizer/SpeechSynthesizerHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/TemplateRuntime/TemplateRuntimeHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/impl/TextToSpeech/TextToSpeechHandler.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ConfigureViewHolder.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/DownloadImageTask.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/LogEntry.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/LogRecyclerViewAdapter.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderBodyTemplate1.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderBodyTemplate2.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderCBLCard.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderCBLExpiredCard.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderListTemplate1.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderLocalSearchDetailTemplate1.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderLocalSearchListTemplate1.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderLocalSearchListTemplate2.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderPreviousWaypointsTemplate.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderRenderPlayerInfo.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderStartNavigationTemplate.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderTextLog.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderTrafficDetailsTemplate.java delete mode 100644 samples/android/app/src/main/java/com/amazon/sampleapp/logView/ViewHolderWeatherTemplate.java delete mode 100644 samples/android/app/src/main/libs/.gitignore delete mode 100755 samples/android/app/src/main/res/drawable-hdpi/ic_action_stop.png delete mode 100644 samples/android/app/src/main/res/drawable-hdpi/ic_action_tap_to_talk.png delete mode 100755 samples/android/app/src/main/res/drawable-mdpi/ic_action_stop.png delete mode 100644 samples/android/app/src/main/res/drawable-mdpi/ic_action_tap_to_talk.png delete mode 100644 samples/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml delete mode 100755 samples/android/app/src/main/res/drawable-xhdpi/ic_action_stop.png delete mode 100644 samples/android/app/src/main/res/drawable-xhdpi/ic_action_tap_to_talk.png delete mode 100755 samples/android/app/src/main/res/drawable-xxhdpi/ic_action_stop.png delete mode 100644 samples/android/app/src/main/res/drawable-xxhdpi/ic_action_tap_to_talk.png delete mode 100644 samples/android/app/src/main/res/drawable/btn_drawer_default.xml delete mode 100644 samples/android/app/src/main/res/drawable/btn_drawer_pressed.xml delete mode 100644 samples/android/app/src/main/res/drawable/btn_drawer_selector.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_selector_next.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_selector_pause.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_selector_play.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_selector_prev.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_selector_skip_backward.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_selector_skip_forward.xml delete mode 100644 samples/android/app/src/main/res/drawable/control_toggle_play_pause.xml delete mode 100755 samples/android/app/src/main/res/drawable/ic_chevron_left.png delete mode 100755 samples/android/app/src/main/res/drawable/ic_chevron_right.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_30sec_back_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_30sec_back_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_30sec_back_enabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_30sec_forward_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_30sec_forward_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_30sec_forward_enabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_loop_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_loop_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_loop_on.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_next_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_next_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_next_focus.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_pause_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_pause_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_pause_focus.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_play_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_play_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_play_focus.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_prev_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_prev_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_prev_focus.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_repeat_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_repeat_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_repeat_on.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_shuffle_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_shuffle_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_shuffle_on.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_thumb_down_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_thumb_down_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_thumb_down_on.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_thumb_up_default.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_thumb_up_disabled.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_control_thumb_up_on.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_down_arrow.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_launcher_background.xml delete mode 100644 samples/android/app/src/main/res/drawable/ic_menu.xml delete mode 100644 samples/android/app/src/main/res/drawable/ic_toggle_loop.xml delete mode 100644 samples/android/app/src/main/res/drawable/ic_toggle_repeat.xml delete mode 100644 samples/android/app/src/main/res/drawable/ic_toggle_shuffle.xml delete mode 100644 samples/android/app/src/main/res/drawable/ic_toggle_thumb_down.xml delete mode 100644 samples/android/app/src/main/res/drawable/ic_toggle_thumb_up.xml delete mode 100755 samples/android/app/src/main/res/drawable/ic_undo.png delete mode 100644 samples/android/app/src/main/res/drawable/ic_up_arrow.png delete mode 100644 samples/android/app/src/main/res/drawable/linear_layout_horizontal_divider.xml delete mode 100644 samples/android/app/src/main/res/layout/activity_main.xml delete mode 100644 samples/android/app/src/main/res/layout/card_body_template1.xml delete mode 100644 samples/android/app/src/main/res/layout/card_body_template2.xml delete mode 100644 samples/android/app/src/main/res/layout/card_list_template1.xml delete mode 100644 samples/android/app/src/main/res/layout/card_list_template1_item_content.xml delete mode 100644 samples/android/app/src/main/res/layout/card_list_template1_item_index.xml delete mode 100644 samples/android/app/src/main/res/layout/card_local_search_detail_template1.xml delete mode 100644 samples/android/app/src/main/res/layout/card_local_search_list_template1.xml delete mode 100644 samples/android/app/src/main/res/layout/card_local_search_list_template1_item.xml delete mode 100644 samples/android/app/src/main/res/layout/card_local_search_list_template2.xml delete mode 100644 samples/android/app/src/main/res/layout/card_local_search_list_template2_item.xml delete mode 100644 samples/android/app/src/main/res/layout/card_lwa_cbl.xml delete mode 100644 samples/android/app/src/main/res/layout/card_lwa_cbl_expired.xml delete mode 100644 samples/android/app/src/main/res/layout/card_previous_waypoints_template.xml delete mode 100644 samples/android/app/src/main/res/layout/card_render_player_info.xml delete mode 100644 samples/android/app/src/main/res/layout/card_start_navigation_template.xml delete mode 100644 samples/android/app/src/main/res/layout/card_traffic_details_template.xml delete mode 100644 samples/android/app/src/main/res/layout/card_weather_template.xml delete mode 100644 samples/android/app/src/main/res/layout/card_weather_template_weather_forecast.xml delete mode 100644 samples/android/app/src/main/res/layout/drawer_switch.xml delete mode 100644 samples/android/app/src/main/res/layout/drawer_view.xml delete mode 100644 samples/android/app/src/main/res/layout/eq_band_control.xml delete mode 100644 samples/android/app/src/main/res/layout/eq_section.xml delete mode 100644 samples/android/app/src/main/res/layout/log_card_container.xml delete mode 100644 samples/android/app/src/main/res/layout/log_item.xml delete mode 100644 samples/android/app/src/main/res/layout/log_view.xml delete mode 100644 samples/android/app/src/main/res/layout/menu_item_talk.xml delete mode 100644 samples/android/app/src/main/res/layout/playback_controller.xml delete mode 100644 samples/android/app/src/main/res/menu/menu_main.xml delete mode 100644 samples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 samples/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml delete mode 100644 samples/android/app/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 samples/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 samples/android/app/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 samples/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 samples/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 samples/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 samples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 samples/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 samples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 samples/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 samples/android/app/src/main/res/raw/med_state_bluetooth_connected.mp3 delete mode 100644 samples/android/app/src/main/res/raw/med_state_bluetooth_disconnected.mp3 delete mode 100644 samples/android/app/src/main/res/raw/med_ui_endpointing.wav delete mode 100644 samples/android/app/src/main/res/raw/med_ui_endpointing_touch.wav delete mode 100644 samples/android/app/src/main/res/raw/med_ui_wakesound.wav delete mode 100644 samples/android/app/src/main/res/raw/med_ui_wakesound_touch.wav delete mode 100644 samples/android/app/src/main/res/values/colors.xml delete mode 100644 samples/android/app/src/main/res/values/strings.xml delete mode 100644 samples/android/app/src/main/res/values/styles.xml delete mode 100644 samples/android/app/src/main/res/xml/network_security_config.xml delete mode 100644 samples/android/app/src/test/java/com/amazon/sampleapp/ExampleUnitTest.java delete mode 100644 samples/android/assets/android_api_key_fields.png delete mode 100644 samples/android/assets/android_sample_add_lwa_lib.png delete mode 100644 samples/android/assets/capabilities.png delete mode 100644 samples/android/assets/finished_dialog.png delete mode 100644 samples/android/build.gradle delete mode 100644 samples/android/gradle.properties delete mode 100644 samples/android/gradlew.bat delete mode 100644 samples/android/modules/sample-apl/.gitignore delete mode 100644 samples/android/modules/sample-apl/build.gradle delete mode 100644 samples/android/modules/sample-apl/gradle.properties delete mode 100644 samples/android/modules/sample-apl/proguard-rules.pro delete mode 100644 samples/android/modules/sample-apl/settings.gradle delete mode 100644 samples/android/modules/sample-apl/src/main/AndroidManifest.xml delete mode 100644 samples/android/modules/sample-apl/src/main/assets/config/APLViewport.json delete mode 100644 samples/android/modules/sample-apl/src/main/assets/sample-app/sample-apl.json delete mode 100644 samples/android/modules/sample-apl/src/main/java/com/amazon/sampleapp/apl/APLFragment.java delete mode 100644 samples/android/modules/sample-apl/src/main/java/com/amazon/sampleapp/apl/APLHandler.java delete mode 100644 samples/android/modules/sample-apl/src/main/java/com/amazon/sampleapp/apl/APLModuleFactory.java delete mode 100644 samples/android/modules/sample-apl/src/main/libs/.gitignore delete mode 100644 samples/android/modules/sample-apl/src/main/res/drawable/customborder.xml delete mode 100644 samples/android/modules/sample-apl/src/main/res/layout/apl_view.xml delete mode 100644 samples/android/modules/sample-connectivity/.gitignore delete mode 100644 samples/android/modules/sample-connectivity/build.gradle delete mode 100644 samples/android/modules/sample-connectivity/gradle.properties delete mode 100644 samples/android/modules/sample-connectivity/settings.gradle delete mode 100644 samples/android/modules/sample-connectivity/src/main/AndroidManifest.xml delete mode 100644 samples/android/modules/sample-connectivity/src/main/assets/sample-app/sample-connectivity.json delete mode 100644 samples/android/modules/sample-connectivity/src/main/java/com/amazon/sampleapp/connectivity/AlexaConnectivityHandler.java delete mode 100644 samples/android/modules/sample-connectivity/src/main/java/com/amazon/sampleapp/connectivity/ConnectivityModuleFactory.java delete mode 100644 samples/android/modules/sample-connectivity/src/main/libs/.gitignore delete mode 100644 samples/android/modules/sample-connectivity/src/main/res/layout/connectivity_view.xml delete mode 100644 samples/android/modules/sample-connectivity/src/main/res/values/colors.xml delete mode 100644 samples/android/modules/sample-connectivity/src/main/res/values/strings.xml delete mode 100644 samples/android/modules/sample-core/.gitignore delete mode 100644 samples/android/modules/sample-core/build.gradle delete mode 100644 samples/android/modules/sample-core/proguard-rules.pro delete mode 100644 samples/android/modules/sample-core/src/main/AndroidManifest.xml delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/AuthStateObserver.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/AuthorizationHandlerFactoryInterface.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/AuthorizationHandlerInterface.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/AuthorizationHandlerObserverInterface.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/EngineStatusListener.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/LoggerControllerInterface.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/ModuleFactoryInterface.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/PropertyListener.java delete mode 100644 samples/android/modules/sample-core/src/main/java/com/amazon/sampleapp/core/SampleAppContext.java delete mode 100644 samples/android/modules/sample-core/src/main/res/values/strings.xml delete mode 100644 samples/android/settings.gradle delete mode 100755 samples/cpp/.gitignore mode change 100755 => 100644 samples/cpp/CMakeLists.txt mode change 100755 => 100644 samples/cpp/README.md delete mode 100644 samples/cpp/SampleApp/CMakeLists.txt delete mode 100644 samples/cpp/SampleApp/include/SampleApp/AddressBook/AddressBookHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/AlertsHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/AlexaClientHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/AlexaSpeakerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/AudioPlayerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/DeviceSetupHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/DoNotDisturbHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/EqualizerControllerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/GlobalPresetHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/LocalMediaSourceHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/NotificationsHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/PlaybackControllerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/SpeechRecognizerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Alexa/TemplateRuntimeHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Audio/AudioInputProviderHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Audio/AudioOutputProviderHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Authorization/AuthorizationHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/CarControl/CarControlHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Communication/CommunicationHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Connectivity/AlexaConnectivityHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/LocalNavigation/LocalSearchProviderHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Location/LocationProviderHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Logger/LoggerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Messaging/MessagingHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Navigation/NavigationHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/Network/NetworkInfoProviderHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/PhoneControl/PhoneControlHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/PropertyManager/PropertyManagerHandler.h delete mode 100644 samples/cpp/SampleApp/include/SampleApp/TextToSpeech/TextToSpeechHandler.h delete mode 100644 samples/cpp/SampleApp/include/gsl/contracts.h delete mode 100644 samples/cpp/SampleApp/include/nlohmann/.clang-format delete mode 100644 samples/cpp/SampleApp/include/nlohmann/json.hpp delete mode 100644 samples/cpp/SampleApp/src/AddressBook/AddressBookHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/AlertsHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/AlexaClientHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/AlexaSpeakerHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/AudioPlayerHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/DeviceSetupHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/DoNotDisturbHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/EqualizerControllerHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/GlobalPresetHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/LocalMediaSourceHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/NotificationsHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/SpeechRecognizerHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Alexa/TemplateRuntimeHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Audio/AudioInputProviderHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Audio/AudioOutputProviderHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Authorization/AuthorizationHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/CarControl/CarControlHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Communication/CommunicationHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Connectivity/AlexaConnectivityHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/LocalNavigation/LocalSearchProviderHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Location/LocationProviderHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Logger/LoggerHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Navigation/NavigationHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/Network/NetworkInfoProviderHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/PhoneControl/PhoneControlHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/PropertyManager/PropertyManagerHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/TextToSpeech/TextToSpeechHandler.cpp delete mode 100644 samples/cpp/SampleApp/src/main.cpp delete mode 100644 samples/cpp/aac-sample-cpp.bb delete mode 100755 samples/cpp/assets/certs/09789157.0 delete mode 100644 samples/cpp/assets/certs/3513523f.0 delete mode 100755 samples/cpp/assets/certs/6d41d539.0 delete mode 100644 samples/cpp/assets/certs/85cf5865.0 delete mode 100755 samples/cpp/assets/certs/8cb5ee0f.0 delete mode 100755 samples/cpp/assets/certs/b204d74a.0 delete mode 100755 samples/cpp/assets/certs/ce5e74ef.0 delete mode 100755 samples/cpp/assets/certs/de6d66f3.0 delete mode 100755 samples/cpp/assets/certs/f387163d.0 delete mode 100644 samples/cpp/assets/config.json.in create mode 100644 samples/cpp/assets/config/config.json rename samples/cpp/assets/{ => menu}/MENU.md (95%) rename samples/cpp/assets/{ => menu}/menu.json (98%) delete mode 100755 samples/cpp/cmake/FindSQLite3.cmake create mode 100644 samples/cpp/cmake/aac-sampleapp.cmake create mode 100644 samples/cpp/conanfile.py rename samples/cpp/{SampleApp => }/include/SampleApp/Activity.h (100%) create mode 100644 samples/cpp/include/SampleApp/AddressBook/AddressBookHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/AlertsHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/AlexaClientHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/AlexaSpeakerHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/AudioPlayerHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/DeviceSetupHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/DoNotDisturbHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/EqualizerControllerHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/LocalMediaSourceHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/MediaPlaybackRequestorHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/NotificationsHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/PlaybackControllerHandler.h create mode 100644 samples/cpp/include/SampleApp/Alexa/SpeechRecognizerHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/Alexa/SpeechSynthesizerHandler.h (89%) create mode 100644 samples/cpp/include/SampleApp/Alexa/TemplateRuntimeHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/Application.h (82%) rename samples/cpp/{SampleApp => }/include/SampleApp/ApplicationContext.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/Args.h (100%) create mode 100644 samples/cpp/include/SampleApp/Audio/AudioInputProviderHandler.h create mode 100644 samples/cpp/include/SampleApp/Audio/AudioOutputProviderHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/Authorization/AuthProviderAuthorizationHandler.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/Authorization/AuthProviderAuthorizationListenerInterface.h (95%) create mode 100644 samples/cpp/include/SampleApp/Authorization/AuthorizationHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/CarControl/BoolController.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/CarControl/CarControlDataProvider.h (100%) create mode 100644 samples/cpp/include/SampleApp/CarControl/CarControlHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/CarControl/ModeController.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/CarControl/RangeController.h (100%) create mode 100644 samples/cpp/include/SampleApp/Communication/AlexaCommsHandler.h create mode 100644 samples/cpp/include/SampleApp/Connectivity/AlexaConnectivityHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/DCM/DCMHandler.h (78%) rename samples/cpp/{SampleApp => }/include/SampleApp/Event.h (99%) rename samples/cpp/{SampleApp => }/include/SampleApp/Executor.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/Extension.h (85%) create mode 100644 samples/cpp/include/SampleApp/LocalNavigation/LocalSearchProviderHandler.h create mode 100644 samples/cpp/include/SampleApp/Location/LocationProviderHandler.h create mode 100644 samples/cpp/include/SampleApp/Logger/LoggerHandler.h create mode 100644 samples/cpp/include/SampleApp/Messaging/MessagingHandler.h create mode 100644 samples/cpp/include/SampleApp/Navigation/NavigationHandler.h create mode 100644 samples/cpp/include/SampleApp/Network/NetworkInfoProviderHandler.h create mode 100644 samples/cpp/include/SampleApp/PhoneControl/PhoneControlHandler.h create mode 100644 samples/cpp/include/SampleApp/PropertyManager/PropertyManagerHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/Status.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/Subject.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/TTY.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/TaskQueue.h (100%) rename samples/cpp/{SampleApp => }/include/SampleApp/TaskThread.h (100%) create mode 100644 samples/cpp/include/SampleApp/TextToSpeech/TextToSpeechHandler.h rename samples/cpp/{SampleApp => }/include/SampleApp/Views.h (100%) rename samples/cpp/{SampleApp => }/src/Activity.cpp (100%) create mode 100644 samples/cpp/src/AddressBook/AddressBookHandler.cpp create mode 100644 samples/cpp/src/Alexa/AlertsHandler.cpp create mode 100644 samples/cpp/src/Alexa/AlexaClientHandler.cpp create mode 100644 samples/cpp/src/Alexa/AlexaSpeakerHandler.cpp create mode 100644 samples/cpp/src/Alexa/AudioPlayerHandler.cpp create mode 100644 samples/cpp/src/Alexa/DeviceSetupHandler.cpp create mode 100644 samples/cpp/src/Alexa/DoNotDisturbHandler.cpp create mode 100644 samples/cpp/src/Alexa/EqualizerControllerHandler.cpp create mode 100644 samples/cpp/src/Alexa/LocalMediaSourceHandler.cpp create mode 100644 samples/cpp/src/Alexa/MediaPlaybackRequestorHandler.cpp create mode 100644 samples/cpp/src/Alexa/NotificationsHandler.cpp rename samples/cpp/{SampleApp => }/src/Alexa/PlaybackControllerHandler.cpp (75%) create mode 100644 samples/cpp/src/Alexa/SpeechRecognizerHandler.cpp rename samples/cpp/{SampleApp => }/src/Alexa/SpeechSynthesizerHandler.cpp (96%) create mode 100644 samples/cpp/src/Alexa/TemplateRuntimeHandler.cpp rename samples/cpp/{SampleApp => }/src/Application.cpp (85%) rename samples/cpp/{SampleApp => }/src/ApplicationContext.cpp (98%) create mode 100644 samples/cpp/src/Audio/AudioInputProviderHandler.cpp create mode 100644 samples/cpp/src/Audio/AudioOutputProviderHandler.cpp rename samples/cpp/{SampleApp => }/src/Authorization/AuthProviderAuthorizationHandler.cpp (99%) create mode 100644 samples/cpp/src/Authorization/AuthorizationHandler.cpp rename samples/cpp/{SampleApp => }/src/CarControl/CarControlDataProvider.cpp (100%) create mode 100644 samples/cpp/src/CarControl/CarControlHandler.cpp create mode 100644 samples/cpp/src/Communication/AlexaCommsHandler.cpp create mode 100644 samples/cpp/src/Connectivity/AlexaConnectivityHandler.cpp rename samples/cpp/{SampleApp => }/src/DCM/DCMHandler.cpp (75%) rename samples/cpp/{SampleApp => }/src/Executor.cpp (100%) rename samples/cpp/{SampleApp => }/src/Extension.cpp (75%) create mode 100644 samples/cpp/src/LocalNavigation/LocalSearchProviderHandler.cpp create mode 100644 samples/cpp/src/Location/LocationProviderHandler.cpp create mode 100644 samples/cpp/src/Logger/LoggerHandler.cpp rename samples/cpp/{SampleApp => }/src/Messaging/MessagingHandler.cpp (85%) create mode 100644 samples/cpp/src/Navigation/NavigationHandler.cpp create mode 100644 samples/cpp/src/Network/NetworkInfoProviderHandler.cpp create mode 100644 samples/cpp/src/PhoneControl/PhoneControlHandler.cpp create mode 100644 samples/cpp/src/PropertyManager/PropertyManagerHandler.cpp rename samples/cpp/{SampleApp => }/src/TaskQueue.cpp (100%) rename samples/cpp/{SampleApp => }/src/TaskThread.cpp (100%) create mode 100644 samples/cpp/src/TextToSpeech/TextToSpeechHandler.cpp rename samples/cpp/{SampleApp => }/src/Views.cpp (99%) create mode 100644 samples/cpp/src/main.cpp create mode 100644 tools/aac-tool-a2ml/conanfile.py create mode 100644 tools/aac-tool-a2ml/src/A2ML/a2ml/generator.py create mode 100644 tools/aac-tool-a2ml/src/A2ML/a2ml/parser.py create mode 100644 tools/aac-tool-a2ml/src/A2ML/a2ml/templates/interface.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/aasb/generator.py create mode 100644 tools/aac-tool-a2ml/src/A2ML/aasb/templates/enum.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/aasb/templates/footer.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/aasb/templates/header.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/aasb/templates/message.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/aasb/templates/struct.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/markdown/generator.py create mode 100644 tools/aac-tool-a2ml/src/A2ML/markdown/templates/interface.tmpl create mode 100644 tools/aac-tool-a2ml/src/A2ML/model.py create mode 100644 tools/aac-tool-a2ml/src/A2ML/processor.py create mode 100755 tools/aac-tool-a2ml/src/a2ml.py diff --git a/.gitignore b/.gitignore index 1c0e6289f..b58132f9b 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ /build # CLion build folder /cmake-build-* -/extras +/extensions/*/** compile_commands.json tools/builder +__pycache__ diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 000000000..50e0e4167 --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,730 @@ +# Build Alexa Auto SDK + +## Supported platforms and architectures + +Auto SDK can be built for the following supported target platforms and hardware architectures: + +* Android 5.1 Lollipop API Level 22 or higher. + * ARM 64-bit + * x86 64-bit +* QNX 7.0 + * ARM 64-bit + * x86 64-bit +* Generic Linux + * x86 64-bit +* Poky Linux + * ARMv7a (+NEON) + * AArch64 +* macOS + * x86 64-bit + +## General build requirements + +You can build the Alexa Auto SDK natively on a Linux or macOS host, or you can use Docker. For specific information about Docker, see [Build in a Docker container](#build-in-a-docker-container). + +The following list describes the supported host configurations: + +* Operating system: + * macOS Sierra + * Ubuntu 18.04 LTS (Bionic) or Ubuntu 20.04 LTS (Focal) +* Processor: 2.5 GHz +* Memory: 16 Gb +* Storage: 1 Gb+ available to use + +## Build dependencies + +To build Auto SDK, you must install the following dependencies on your host machine: + +### General + +- [Python 3.7](https://www.python.org/downloads) +- [Conan 1.33](https://conan.io/downloads.html) +- [CMake 3.12](https://cmake.org/install) + +### Linux + +- GCC +- GStreamer (see [Install GStreamer](#install-gstreamer)) + +### macOS + +- Xcode + +## Understand the build system + +Building software for multiple platforms can be complex because specific toolchains might vary depending on the build system and target platform. In general, there are two flavors of builds: native and cross-compiled. In a native build, the build system uses its own toolchain and libraries to build the software, so the compiled software can run on the platform that built it. In cross-compilation, the build system typically uses an installed toolchain to compile the software for a different target platform. It's possible that more than one toolchain is installed on a system, so extra steps are typically needed to cross-compile to those targets. Auto SDK uses [Conan](https://conan.io), along with other tools and scripts described in this section, to manage the complexities required to implement a complete build system. + +### Conan + +The Auto SDK build system uses Conan as its underlying package manager and build configuration tool. For every Conan package, there is a recipe that defines the dependencies of the package and specifies how to download and build the package source code. After building a package, Conan copies the binaries and other artifacts into a cache directory so other recipes that depend on that package can use the prebuilt binaries without rebuilding them. When a Conan recipe defines a dependency, Conan finds and builds the dependency as required, taking care of complexities such as transitive requirements, package version conflicts, and managing multiple versions of a package built with different configurations. + +Before using a package, Conan must export or download the package into the local cache. When a package recipe exists in the same local repository as the source code it builds, as is the case when you download Auto SDK, you must run `conan create` or `conan export` before other recipes can build the package. Community servers such as [Conan Center](https://conan.io/center) host some popular third party libraries, however, so Conan automatically downloads them to the local cache as needed. Auto SDK requires a combination of Conan packages including local recipes for Auto SDK modules and tools, local recipes for third party packages, and third party packages hosted on the Conan Center server. + +Once Conan copies a package into the local cache, a recipe can build or consume the package based on the specified build configuration. Conan will build a new package version if the package version is required and missing from the cache. For example, if you build Auto SDK for Linux, Conan will build all of the required packages for the specified Linux target. If you then build for an Android target, Conan will rebuild all of the required packages for the Android target and cache both the Linux and Android versions. In addition to target platform, any option or setting that you specify when building a recipe affects the package version. + +#### Auto SDK modules + +Auto SDK includes a base Conan recipe class that all Auto SDK modules extend. This is defined in `conan/recipes/aac-sdk-tools`, and must be exported before other modules since it is required by each module's recipe definition. The base recipe defines common build options, and relies on specific conventions in the module's directory structure to find source files and headers, and to generate other artifacts that are needed at build time. A simple Conan recipe is required for each module to override abstract values in the base class (such as the module name), and to define any module specific dependencies or options that are required. A module can also define it's own CMake files, unique configuration, or even custom build steps as needed. + +For each module, the base recipe defines common options that are used to specify which components are included in the library. The default values provided in the base recipe should be used in most cases when you are building release libraries for production. For some cases, however, you may want to enabled features such as `with_sensitive_logs` or `with_unit_tests`, to add additional information when debugging issues with the libraries. To find out which options are defined for a specific module, you can use the `conan inspect` command to display information about any Conan recipe. This command will display all of options and default values for a recipe, including any options that are inherited from the base module recipe. See the [Specify build settings and options](#specify-build-settings-and-options) section in this guide, for more information. + +Applications integrate with Auto SDK using the MessageBroker API, by publishing and subscribing to specific message topics and actions (see [Using the MessageBroker API](./modules/core/README.md)). Most modules provide interfaces that require these messages to be defined, in which case they will include one or more message definition files in the `aasb/messages` directory of the module. The model created by the message definitions are used when building Auto SDK to generate message headers that are required to build the module, and are also used to create documentation for each message interface. + +#### Third party dependencies + +Auto SDK has dependencies on several third party packages (libraries and build tools for example), which may themselves have dependencies on other packages. In general, managing these types of build requirements can be very complex for a large project. Conan helps by providing community hosted recipes for many common packages, as well as by allowing developers to create there own package recipes. It is important to understand that some of the packages used by Auto SDK are pulled from the Conan Center remote server, while others are defined locally in the `conan/recipes` directory of Auto SDK. Local recipes are typically required when the package does not already exist on Conan Center, or there are specific patches or changes to the recipe that are needed for Auto SDK. + +### Builder Tool + +The Builder Tool is a script that can be used to build Auto SDK libraries for supported platforms. It improves the build process by wrapping underlying Conan commands and options with a simple command line interface. Although it is possible to use Conan by itself to build Auto SDK - see the [Build with Conan directly](#build-with-conan-directly) section of this guide, it is recommended to use the Builder Tool for common build tasks. + +### Alexa Auto Client Service + +Alexa Auto Client Service (AACS) is an Android service library that simplifies the process of integrating Auto SDK on Android-based devices. AACS has a dependency on Auto SDK native Android libraries, but can be built independently using standard Android development tools. For more information about building AACS, see the [Building AACS with AACS Sample App](./aacs/android/sample-app/README.md#building-the-aacs-sample-app-using-aacs-aar) section of the [Alexa Auto Client Service](./aacs/android/README.md) guide. + +## Build with Builder Tool + +The Builder Tool script, `build.py` is located in the `builder` directory of the SDK. It wraps underlying Conan commands, and simplifies building libraries for Auto SDK modules on supported platforms. Individual modules, components, and dependencies in the SDK are described as packages in the builder. Each package has a corresponding Conan recipe that is used to build and deploy the package to the cache located in the builder's home directory. An archive containing all of the specified build artifacts is created from the cache, and written to the `deploy` directory of the builder, after the build has completed. This section descibes the most common commands used to build Auto SDK. For a complete reference to the Builder Tool command line interface, see [Builder Tool command reference](./builder/README.md). + +Auto SDK currently supports native builds for Ubuntu Linux (x86_64) and MacOS, and building for each platform follows the same steps. After cloning the Auto SDK git repository on your system, the following examples should be run with `aac-sdk` as the working directory. + +The following command will build all of the modules that are included in the Auto SDK repository, along with any dependencies that are required for the target platform: + +```shell +$ ./builder/build.py +``` + +When you run the build command, the builder tool will export and configure any new build artifacts, such as package recipes or configuration files, that are discovered in the search path. The first time you run (or after cleaning the build cache), you'll see several log messages indicating that the build recipes are being exported to the local cache: + +```shell +[BUILDER] INFO: Python version: 3.7.3 +[BUILDER] INFO: Cleaning cached builder data +[BUILDER] INFO: Builder home: ../aac-sdk/builder/.builder +[BUILDER] INFO: Conan home: ../aac-sdk/builder/.builder/.conan +[BUILDER] INFO: Gradle home: ../aac-sdk/builder/.builder/.gradle +[BUILDER] INFO: Configuring Conan... +[BUILDER] INFO: Installing Conan configuration: ../aac-sdk/conan/config +[BUILDER] INFO: Exporting recipe: aac-sdk-tools +[BUILDER] INFO: Exporting recipe: aac-module-core +[BUILDER] INFO: Exporting recipe: aac-module-alexa +[BUILDER] INFO: Exporting recipe: aac-module-cbl +[BUILDER] INFO: Exporting recipe: android-sdk-tools +[BUILDER] INFO: Exporting recipe: avs-device-sdk +... +``` + +The builder keeps track of which recipes have already been added to the cache, so that the next time you run the build command only new recipes will be exported. It is possible, however, to tell the builder to force re-exporting a recipe (using the `-f` or `--force` option), and build it if necessary. The following command will force all Auto SDK module recipes to be re-exported: + +```shell +$ ./builder/build.py -f "aac-module-*" +``` + +To explicitly force one or more recipes to be exported, you can specify the name of the module (or explicit package name) that you want. The following example will force the builder to re-export and build only the `alexa` and `cbl` modules. + +```shell +$ ./builder/build.py -f alexa cbl +``` + +Each time the builder is run, it will also attempt to re-configure Conan settings by initializing the Conan configuration and installing any config files found in the search path. This happens every time because it is possible, using Docker for example, to re-use the Conan home path when building with a different build system configuration. This step ensures that the Conan configuration will match the build system currently being used. In the case that you want to skip the configuration step for some reason (maybe you have overridden configuration settings in the Conan home manually), you can tell the builder to skip the configuration step using the `--skip-config` option: + +```shell +$ ./builder/build.py --skip-config +``` + +### Specify the build target + +Auto SDK can be cross-compiled for supported target systems by specifying the platform and architecture with the build command. Android and QNX targets can be built on either Linux or macOS, and Poky must be built using Linux. For information about specific build target requirements, see the [Platform-specific build information](#platform-specific-build-information) section of this guide. To set the target platform using the Builder Tool, specify the `--platform,-p ` option when doing a build: + +```shell +$ ./builder/build.py -p android +``` + +You can also set the target architecture by specifying the `--arch,-a ` option: + +```shell +$ ./builder/build.py -p android -a x86_64 +``` + +The following table defines the supported platforms and architectures. + +|platform |arch | +|---------|---------------------------| +|android |armv8, x86_64 | +|qnx |armv8, x86_64 | +|poky |armv8, armv7hf, x86_64, x86| + +### Specify which modules to build + +If you are using a subset of modules in Auto SDK, you can specify which modules to build on the command line using the `-m` or `--modules` option followed by a list of modules names. Dependent modules and libraries will be included transitively when specifying which modules to build. The following example will build the `core`, `alexa`, and `cbl` modules, and package them into the output archive: + +```shell +$ ./builder/build.py -m core alexa cbl +``` + +You can verify which modules were specified in the build by looking at the `[requires]` section or `pkg_modules` option value in the `aac-buildinfo.txt` file: + +``` +[requires] + aac-module-alexa/dev + aac-module-cbl/dev + aac-module-core/dev + +[options] + ... + pkg_modules=aac-module-core/dev,aac-module-alexa/dev,aac-module-cbl/dev +``` + +You could also build the same modules by specifying the following on the command line: + +```shell +$ ./builder/build.py -m cbl +``` + +This works because the `cbl` module depends on the `alexa` module, which depends on the `core` module - so even though they are not specified on the command line, `core` and `alexa` are transitively included. The `aac-buildinfo.txt` file will only show the `cbl` module under the `[requires]` section, however, the full list of included dependencies can be found under the `[full_requires]` section in the build info: + +``` +[full_requires] + aac-module-alexa/dev:1de4d8ddd6d19b16b05d95052195f9556361e7b5 + aac-module-cbl/dev:8b2bd324ad68ca44682ed4ed11f0845ef8df1a5c + aac-module-core/dev:fe4587e72f3350cdb9dab53b293dfee0d5575a0a + ... +``` + +### Clean build artifacts + +Conan caches binaries and artifacts for each package after it is built, so they can be used as dependencies by other packages without having to be re-built each time. If you make changes to the source code in the SDK, however, you must either explicitly force the builder to re-export and build the package (using the `--force,-f ` option of the builder), or remove the package entirely from the cache. To remove packages from the cache using the Builder Tool, you can use the `clean` command: + +```shell +$ ./builder/build.py clean +``` + +You must specify the package name or regex-style pattern to clean. For example, to remove all of the packages from the cache, you can use the following command: + +```shell +$ ./builder/build.py clean "*" +``` + +To remove a specific module, you can either specify the package name or just the module's name: + +```shell +$ ./builder/build.py clean alexa +``` + +Since the convention used by Auto SDK is to specify the module's package name as `aac-module-`, you can also use the full package name as part of the pattern. One way to remove all Auto SDK modules from the cache would be to use the following command: + +```shell +$ ./builder/build.py clean "aac-module-*" +``` + +If a package has been removed from the cache, the Builder Tool will automatically detect that it needs to be re-exported and built the next time you do a build, and it is not necessary to specify the package using the `--force` option. + +### Build debug libraries + +Building debug libraries for Auto SDK can be specified by using the `--debug` or `-g` option when doing a build: + +```shell +$ ./builder/build.py -g +``` + +When this option is used, debug libraries for all of the Auto SDK modules and dependencies will be built if required, and exported to the build archive. If you want more specific control over which debug libraries to use, you can specify the `build_type` option as a Conan setting instead, using the `--conan-setting,-s =` build option. For example, to use debug libraries only for Auto SDK modules, you can use the following build command: + +```shell +$ ./builder/build.py -s "aac-module-*":build_type=Debug +``` + +This is a less common use case, however, that requires you to be familiar with some of the underlying Conan build architecture. To learn more about some of the Conan specific options for building Auto SDK, see the [Build with Conan directly](#build-with-conan-directly) section of this guide. + + +### Locate the build output + +When you run the builder tool, all of the shared libraries and dependencies will be saved in an archive file in the `builder/deploy` directory by default. The name of the archive file is displayed in the console when the build is completed: + +```shell +[BUILDER] INFO: Created output archive: ../aac-dev-macos_x86_64-release-210706140415.tgz +``` + +The default name of the archive indicates the following information that is used to build the SDK: + +``` +aac--_--.tgz +``` + +Sometimes it is helpful to tag a build with an identifier, for example, if you want to indicate a build was made for a specific purpose. If you want to add an additional identifier to the archive name, you can use `--name` option when running the build tool: + +```shell +$ ./builder/build.py --name test +... +[BUILDER] INFO: Created output archive: ../aac-dev-test-macos_x86_64-release-210706142403.tgz +``` + +It is also possible to completely override the output file name and path by specifying the `-o` or `--output` option on the command line: + +```shell +$ ./builder/build.py --output /mypath/custom-output.tgz +... +[BUILDER] INFO: Created output archive: /mypath/custom-output.tgz +``` + +If you don't want the builder to generate an output archive at all, you can specify the `--no-output` option on the command line. This is helpful if you just want to re-build one or more module, for example, to run unit tests or inspect the package libraries: + +```shell +$ ./builder/build.py --no-output +``` + +#### Archive contents + +The output archive created by the Builder Tool includes all of the build artifacts from the modules and dependencies specified by the build command. You can extract the archive with the following command (the exact filename will be slightly different for your build): + +```shell +$ tar -xvzf builder/deploy/aac-dev-linux_x86_64-release.tgz +``` + +After you can extract the contents of the archive, there should be a directory with contents similar to the following file structure: + +``` +aac-dev-linux_x86_64-release/ + ├─ docs/ + ├─ include/ + ├─ lib/ + | ├─ libAACECore.so + | └─ ... + ├─ share/ + └─ aac-buildinfo.txt +``` + +You can get additional information about the archive contents from a description file in the archive named `aac-buildinfo.txt`. The build description file can be used to identify which modules, settings, and options were used to generate the libraries by the build. The following is an example of the information found in the build description file: + +``` +[settings] + arch=x86_64 + build_type=Release + compiler=apple-clang + compiler.libcxx=libc++ + compiler.version=11.0 + os=Macos + +[requires] + aac-module-aasb/dev + aac-module-address-book/dev + aac-module-alexa/dev + aac-module-car-control/dev + aac-module-cbl/dev + aac-module-connectivity/dev + aac-module-core/dev + aac-module-messaging/dev + aac-module-navigation/dev + aac-module-phone-control/dev + aac-module-text-to-speech/dev + +[options] + aac_version=dev + with_sensitive_logs=False + pkg_modules=aac-module-aasb/dev,aac-module-address-book/dev,aac-module-alexa/dev,... + with_aasb=False + +[full_settings] + arch=x86_64 + build_type=Release + compiler=apple-clang + compiler.libcxx=libc++ + compiler.version=11.0 + os=Macos + +[full_requires] + aac-module-aasb/dev:4990d7e4c95bbcae311c6d13cb0e71a09ecd2f43 + aac-module-address-book/dev:8b2bd324ad68ca44682ed4ed11f0845ef8df1a5c + aac-module-alexa/dev:1de4d8ddd6d19b16b05d95052195f9556361e7b5 + ... +``` + +## Build with Conan directly + +Conan can be used directly to build Auto SDK components and other package dependencies, or to use Auto SDK libraries in other Conan recipes. It's helpful to have a good general understanding of how Conan works first, and also to understand the basic Auto SDK build system. The examples in this section should be run with `aac-sdk` as the working directory. + +### Export Conan recipes + +The following script will find all of the Conan recipes in Auto SDK and export them to the local cache. Package binaries won't actually be built until they are required by another recipe during a build operation, or explicitly built by running the `conan create` command. This is a convenience script and is not required if you want to export or create packages individually. + +```shell +$ ./conan/setup.py +``` + +If you want to export a single package individually, you can run the `conan export` command. For example, to export the alexa module to the local cache: + +```shell +$ conan export modules/alexa +``` + +It is important to understand that exporting a module using the `conan export` command does not automatically find and export any of the dependent packages specified in the recipe. Attempting to build the alexa module would fail, unless all of the requirements can be resolved in the local cache. Running the `conan/setup.py` script is usually the safest option to ensure all required packages are copied to the cache, however, exporting a package individually can save time after you make changes, if you have previously exported all of the packages. + +### Build modules + +In most cases it shouldn't be necessary to manually build Auto SDK modules, since Conan can build missing dependencies when required by another recipe. It is possible, however, to create/build a package independently using Conan if needed. The following example shows how to create the Alexa module package from the command line: + +```shell +$ conan create modules/alexa --build missing +``` + +The `conan create` command tells conan to create a new binary package from a recipe file and install it in the local cache. In the example above, `modules/alexa` refers to the parent directory in Auto SDK (`aac-sdk/modules/alexa`), where the `conanfile.py` recipe is located for the Alexa module. + +By specifying the `--build missing` option, Conan will automatically build dependencies where a binary package is missing for the specified build configuration. If the dependency has already been created it will not be built again. + +Using the `--build` flag without any additional options will force all of the dependencies to be rebuilt, even if the binary for the specified configuration already exists. + +### Specify build settings and options + +When you build a Conan package, you can specify settings and options that result in different binaries when the source code is built. Conan `settings` are project-wide configurations, such as `os`, `compiler`, `build_type`, and `arch`. These settings should be applied to each package when selecting the correct binary. Most of the time, settings will be applied based on the selected (or default) profile. To view or modify a profile, you can use the `conan profile` command. To show the default profile values, you can enter the following command: + +```shell +$ conan profile show default + +Configuration for profile default: + +[settings] +os=Macos +os_build=Macos +arch=x86_64 +arch_build=x86_64 +compiler=apple-clang +compiler.version=11.0 +compiler.libcxx=libc++ +build_type=Release +[options] +[build_requires] +[env] +``` + +You usually don't need to change settings specified in the profile, but if needed, you can override any setting value when running a Conan command. For example, to build a debug version of the alexa module, you can add `-s build_type=Debug` to the `conan create` command: + +```shell +$ conan create modules/alexa -b missing -s build_type=Debug +``` + +Individual packages can also define `options` which are specific to it's own build requirements. One common option that most packages define is `shared`, which is used to build either the static or dynamic library. Options can also be used to specify conditional features which should be included in the build, for example, `libcurl` defines an option called `with_nghttp2` to specify that the build should include support for `http2`. + +#### Inspect package recipes + +To see which options a recipe has defined, you can use the `conan inspect` command: + +```shell +$ conan inspect modules/alexa/conanfile.py + +name: aac-module-alexa +version: dev +url: https://github.com/alexa/alexa-auto-sdk +homepage: None +license: Apache-2.0 +author: None +description: Auto SDK module: alexa +topics: None +generators: cmake +exports: None +exports_sources: * +short_paths: False +apply_env: True +build_policy: None +revision_mode: hash +settings: ('os', 'compiler', 'build_type', 'arch') +options: + message_version: ANY + shared: [True, False] + with_aasb: [True, False] + with_address_sanitizer: [True, False] + with_android_libs: [True, False] + with_coverage_tests: [True, False] + with_docs: [True, False] + with_engine: [True, False] + with_jni: [True, False] + with_latency_logs: [True, False] + with_messages: [True, False] + with_platform: [True, False] + with_sensitive_logs: [True, False] + with_unit_tests: [True, False] +default_options: + message_version: 4.0 + shared: True + with_aasb: True + with_address_sanitizer: False + with_android_libs: True + with_coverage_tests: False + with_docs: True + with_engine: True + with_jni: True + with_latency_logs: False + with_messages: True + with_platform: True + with_sensitive_logs: False + with_unit_tests: False +deprecated: None +``` + +This command shows different attributes of the package, including its `options` and the default values for each option specified in `default_options`. To override a default option when building a package, you can add `-o [option]=[value]`. If you want to override an option for a specific package, then you can specify the package name as well, `-o [pkg]:[option]=[value]`. For example, to build and run unit tests for the alexa module, you can add `-o with_unit_tests=True` to the `conan create` command: + +```shell +$ conan create modules/alexa -b missing -o with_unit_tests=True +``` + +### Remove packages from the cache + +Packages can be removed from the local cache if needed by using the `conan remove` command. For example, the following command can be used to remove the alexa module from the cache: + +```shell +$ conan remove aac-module-alexa -f +``` + +The `-f` option is used to remove the package without confirmation. To remove all Auto SDK modules from the cache, you can specify the following pattern `aac-module-*` in place of a package name, or specify `*` to remove all packages: + +```shell +$ conan remove "aac-module-*" -f +$ conan remove "*" +``` + +> **Note:** when specifying a wildcard in the package name, you must surround the pattern with quotes. + +### Use Auto SDK in other recipes + +If you have your own project that uses Conan, to build an application or library for example, you can include Auto SDK packages in the requirements section of your Conan recipe. The following example shows how you can include Auto SDK modules that are built on the same development machine, in a `conanfile.txt` recipe: + +``` +[requires] +aac-module-core/dev +aac-module-alexa/dev +aac-module-cbl/dev +aac-module-system-audio/dev +... +``` + +When you build your package, as long as the Auto SDK packages have been exported to the local cache, Conan will include the specified modules when building your project. It is important to note the convention used by Auto SDK, where all module packages are named `aac-module-`, and the default package version when building locally will be `dev` unless overridden at build time. + +You can add Auto SDK modules as a requirement to `conanfile.py` recipes as well, by specifying them using the `requires` attribute in the recipe: + +```python +class ConanRecipe(ConanFile): + requires = + ["aac-module-core/dev","aac-module-alexa","aac-module-cbl/dev","aac-module-system-audio/dev"] + ... +``` + +## Platform-specific build information + +### Android + +Android can be cross-compiled on either MacOS or Linux, using the NDK toolchain build requirement specified in the `aac-android` profile. To build Android compatible binaries with the Builder Tool, simply use the `--platform` or `-p` option to specify the `android` platform. + +```shell +$ ./builder/build.py -p android +``` + +By default the android configuration used to build the SDK is defined in the `aac-android` Conan profile: + +``` +[settings] +os=Android +os.api_level=26 +arch=armv8 +build_type=Release +compiler=clang +compiler.libcxx=libc++ +compiler.version=8 + +[build_requires] +android-sdk-tools/4.0@aac-sdk/stable +``` + +You can override default target architecture to build either the `armv8`, or `x86_64` version of the binaries by specifying the `--arch` or `-a` option on the command line: + +```shell +$ ./builder/build.py -p android --arch=x86_64 +``` + +> The first time you build Auto SDK for Android, the Android SDK must be downloaded and installed. This is handled by the `android-sdk-tools` recipe in Auto SDK when you build, however, several license agreements must be manually accepted before any of the Android tools can be used. These agreements will need to be accepted anytime you change the builder home directory, or clean the builder cache as well. You can optionally accept all of the license agreements by specifying `-y` or `--accept-licenses` when running the builder from the command line. + +If you are using Conan directly to build Auto SDK libraries, you must specify the `--profile:host,-pr:b` and `--profile:build,-pr:b` options as part of the build command. In this case for Android, you would specify `aac-android` as the host (target) profile in your build command, in addition to explicitly specifying `default` as the build profile: + + +```shell +$ conan create modules/alexa -pr:h aac-android -pr:b default -b missing +``` + +You can override any setting for the target platform on the command line, for example, to build the `x86_64` version of the Android libraries you can specify `-s:h arch=x86_64` as an option: + +```shell +$ conan create modules/alexa -pr:h aac-android -pr:b default -b missing -s:h arch=x86_64 +``` + +### Ubuntu + +Building Auto SDK for Linux on Ubuntu requires installing some additional dependencies, such as GStreamer if you are using the `system-audio` module. + +#### Install GStreamer + +The `system-audio` module uses GStreamer to implement the core audio interfaces, and must be installed prior to building. The following command will install the dependencies required to build with GStreamer: + +```shell +$ apt install -y \ + pkg-config libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ + libgstreamer-plugins-bad1.0-dev gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \ + gstreamer1.0-plugins-ugly gstreamer1.0-libav gstreamer1.0-doc \ + gstreamer1.0-tools gstreamer1.0-x gstreamer1.0-alsa gstreamer1.0-gl \ + gstreamer1.0-gtk3 gstreamer1.0-qt5 gstreamer1.0-pulseaudio +``` + +#### Update the default Conan profile + +You might run into an issue on Ubuntu where Conan does not detect the default `libstdc++11` setting properly, so it is recommended to check this when setting up your host environment. You can run the following command to update the default Conan profile to use the `libstdc++11` compiler option: + +```shell +$ conan profile new default --detect +$ conan profile update settings.compiler.libcxx=libstdc++11 default +``` + +### Poky + +Poky can be cross compiled on Linux using the host Poky SDK toolchain. To build Poky compatible binaries with the Builder Tool, simple use the `--platform` or `-p` option to specify the `poky` platform. + +```shell +$ ./builder/build.py -p poky +``` + +By default the poky configuration used to build the Auto SDK is defined in the aac-poky Conan profile: + +``` +[settings] +compiler.version=8.2 +arch=armv7hf +build_type=Release +os=Linux +compiler.libcxx=libstdc++11 + +[build_requires] +poky-sdk/2.6.1 +``` + +You can override default target architecture to build either the `armv7hf`, or `armv8` version of the binaries by specifying the `--arch` or `-a` option on the command line: + +```shell +$ ./builder/build.py -p poky --arch=armv8 +``` + +> The first time you build Auto SDK for Poky, the Poky SDK must be downloaded and installed. This is handled by the `poky-sdk` recipe in Auto SDK when you build, however, several license agreements must be manually accepted before the Poky SDK can be used. These agreements will need to be accepted anytime you change the builder home directory, or clean the builder cache as well. You can optionally accept all of the license agreements by specifying `-y` or `--accept-licenses` when running the builder from the command line. + +If you are using Conan directly to build Auto SDK libraries, you must specify the `--profile:host,-pr:h` and `--profile:build,-pr:b` options as part of the build command. In this case for Poky, you would specify `aac-poky` as the host (target) profile in your build command, in addition to explicitly specifying default as the build profile: + +```shell +$ conan create modules/alexa -pr:h aac-poky -pr:b default -b missing +``` + +You can override any setting for the target platform on the command line, for example, to build the `armv8` version of the Poky libraries you can specify `-s:h arch=armv8` as an option: + +```shell +$ conan create modules/alexa -pr:h aac-poky -pr:h default -b missing -s:h arch=armv8 +``` + +### QNX + +QNX can be cross compiled on Linux or MacOS using the host QNX SDP tools. To build QNX, you must install the [QNX 7.0 SDP](http://blackberry.qnx.com/en/sdp7/sdp70_download) on your host as a prerequisite. To build QNX compatible binaries with the Builder Tool, simply use the `--platform` or `-p` option to specify the `qnx` platform: + +```shell +$ ./builder/build.py -p qnx +``` + +By default the QNX configuration used to build the Alexa Auto SDK is defined in the `aac-qnx` Conan profile: + +``` +[settings] +os=Neutrino +os.version=7.0 +arch=armv8 +compiler=qcc +compiler.version=5.4 +compiler.libcxx=cxx +compiler.cppstd=None + +[build_requires] +qnx-cross-compiling/7.0.0 +[options] +[env] +``` + +You can override default target architecture to build either the `armv8`, or `x86_64` version of the binaries by specifying the `--arch` or `-a` option on the command line: + +```shell +$ ./builder/build.py -p qnx --arch=x86_64 +``` + +The Conan recipe assumes that the QNX SDP is installed in your home director: `~/qnx700`, but you can override this by setting the `qnx7sdp_path` option using the `--conan-option` or `-o` argument on the command line: + +```shell +$ ./builder/build.py -p qnx -o qnx7-sdp:qnx7sdp_path=/path/to/qnx7sdp +``` + +### macOS + +macOS can be used as a build host for cross-compiled Android and QNX targets, as well and target for native development and testing. + +#### GStreamer build issue + +There is a known issue where building GStreamer can fail due to a conflict with `openEXR` on macOS. This may be an issue if you are seeing the following type of errors in your build output: + +```shell +In file included from ../source_subfolder/ext/openexr/gstopenexrdec.cpp:30: +In file included from /usr/local/include/OpenEXR/ImfRgbaFile.h:23: +In file included from /usr/local/include/OpenEXR/ImfHeader.h:22: +In file included from /usr/local/include/Imath/ImathVec.h:17: +/usr/local/include/Imath/ImathMath.h:152:36: error: expected ';' at end of declaration +equalWithAbsError (T x1, T x2, T e) IMATH_NOEXCEPT + ^ +``` + +Uninstalling `openEXR` has been reported to solve the problem: + +```shell +$ brew uninstall --ignore-dependencies openEXR +``` + +### Windows + +> Windows is not currently supported as a build host or target. + +## Build in a Docker container + +You can use Docker for native Linux builds, or any cross-compiler target that is supported with Linux, as long as the Docker container has the required build dependencies installed. For convenience, you can use the `aac-ubuntu-bionic` or `aac-ubuntu-focal` containers provided in the `conan/docker` directory of the SDK. The following commands should be run with `aac-sdk` as the working directory. + +Create the `aac-ubuntu-bionic` docker image: + +```shell +$ docker build -t aac/ubuntu-bionic conan/docker/aac-ubuntu-bionic +``` + +Build Auto SDK using the Builder Tool: + +```shell +$ docker run -it -v$(pwd):/home/conan/aac-sdk --rm \ + aac/ubuntu-bionic /bin/bash -c "aac-sdk/builder/build.py" +``` + +The option `-v$(pwd):/home/conan/aac-sdk` specifies that we want to mount the current directory on the host machine (which should be the Auto SDK root), to `/home/conan/aac-sdk` in the Docker container file system. After starting the container, you will be able to build Auto SDK using Conan with the same commands used on your host machine. + +When the build is complete, the output archive file will be saved to the mounted `aac-sdk/builder/deploy` directory of your host machine. If you inspect `aac-buildinfo.txt` in the archive, you should see that the libraries were built for `os=Linux, arch=x86_64`: + +``` +[settings] + arch=x86_64 + build_type=Release + compiler=gcc + compiler.libcxx=libstdc++11 + compiler.version=7 + os=Linux +``` + +### Optimize build performance + +When you build Auto SDK using a Docker container it can take much longer to build than it would natively on your host computer. This is because the Builder Tool home directory is specified as `aac-sdk/builder` by default, which is a directory on the host file system. File operations in general are much slower when running on a mounted volume, so this will impact the build performance. One option is to specify a different home directory on the container's volume when running the build command instead. This will greatly improve the build time, however, you should be aware that when you remove the container the cached build artifacts may be lost. The Builder Tool will still write the output archive to `aac-sdk/builder/deploy` on the mounted volume by default, even if the home directory is changed. + +The following example shows how you can set the home directory using the `--home` option, when doing a build using Docker: + +```shell +$ docker run -it -v$(pwd):/home/conan/aac-sdk --rm \ + aac/ubuntu-bionic /bin/bash -c "aac-sdk/builder/build.py --home /home/conan" +``` diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a9d7a00c..adfaaf23e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,19 +1,180 @@ # Change Log ___ + +## v4.0.0 released on 2021-12-15 + +### Enhancements + +* Deprecated the C++ and Java platform interfaces in favor of an asynchronous message-based API. Auto SDK client applications use the new `MessageBroker` to publish and subscribe to Alexa Auto Services Bridge (AASB) messages. The C++ sample app is refactored to use the new API to provide a reference implementation for Linux platforms. The Alexa Auto Client Service (AACS) sample app provides the reference implementation for Android platforms. See the [Auto SDK Migration Guide](./MIGRATION.md) for help migrating your application to use the new API. + +* Enhanced the Auto SDK build system with the Conan package manager. The new build system introduces modular builds, better dependency management, and simpler build artifacts. The Auto SDK build system includes the Auto SDK Builder Tool script, which wraps the Conan build commands with a simple interface similar to the previous version of Auto SDK Builder. See the [Build Alexa Auto SDK documentation](./BUILDING.md) for details about the build system and the [Migration Guide](./MIGRATION.md) for help migrating your build to the new version of Builder Tool. + +* Extended the features of Alexa Presentation Language (APL) support for automotive. The `APL` module provides messages to report vehicle properties such as the display theme, driving state, and ambient light conditions. The property settings affect how APL documents render on screen; for example, some APL content is automatically hidden when the vehicle starts moving, and the display contrast updates with the day or night mode setting. Auto SDK 4.0 supports APL 1.9. For more information about the Auto SDK `APL` interface, see the [APL module documentation.](./modules/apl/README.md) + +* Added the `CustomDomain` interface, which establishes a bidirectional communication channel between your Auto SDK client application and your custom cloud skill. `CustomDomain` includes messages for exchanging directives, events, and context between the vehicle and your skill, achieving a fully customizable experience. For more information about the Auto SDK `CustomDomain` interface, See the [Custom Domain module documentation.](./modules/custom-domain/README.md) + +* Added the `MediaPlaybackRequestor` interface, which enables Alexa to play the user’s favorite media content as soon as they start their vehicle. `MediaPlaybackRequestor` simplifies content selection for the user by removing the need for the user to use buttons or voice commands to resume the Alexa media content that was playing when they stopped the vehicle. For more information about the Auto SDK `MediaPlaybackRequestor` interface, See the [Alexa module documentation.](./modules/alexa/README.md) + +* Extended the `AudioOutput` interface and added configuration to allow ducking Alexa media. Your application can use this feature for enhanced control of Alexa content audio focus according to your platform requirements. For more information about audio ducking, see the [Core module documentation.](./modules/core/README.md) + +* Updated the Auto SDK to use AVS Device SDK Version 1.25.0. For information about this version of AVS Device SDK, see the [AVS Device SDK release notes.](https://developer.amazon.com/en-US/docs/alexa/avs-device-sdk/release-notes.html#version-1250) + +* Added LVC support for Alexa Custom Assistant specialized handoffs. You can configure the default fallback and self-introduction prompts for your custom assistant while offline. For more information, see the `Alexa Custom Assistant` extension documentation. + +* Integrated the Auto SDK Conan build system enhancements to AACS and the AACS sample app. You can use a single Gradle command to build AACS and the AACS sample app. For build instructions, see the [AACS documentation.](./aacs/android/README.md) + +* Added the following enhancements to the AACS sample app: + + * **Additional languages—** The AACS sample app supports the following languages: *US English* (`en-US`), *Australian English* (`en-AU`), *Canadian English* (`en-CA`), *Indian English* (`en-IN`), *British English* (`en-GB`), *German* (d`e-DE`), *Spanish* (`es-ES`), *Mexican Spanish* (`es-MX`), *US Spanish* (`es-US`), *French* (`fr-FR`), *Canadian French* (`fr-CA`), *Hindi* (`hi-IN`), *Italian* (`it-IT`), *Japanese* (`ja-JP`), and *Brazilian Portuguese* (`pr-BR`). + + The sample app language setting matches the device’s system language setting and syncs the with Alexa as long as the setting is in the supported language list. If Alexa does not support the system language, the sample app GUI defaults to en-US and presents a list of languages for the user to choose from. Once the user selects the language override, the system language does not sync with the sample app again until the user logs out or disables Alexa. + + * **Network error prompts—** You can configure the sample app to provide feedback to the user when Alexa cannot respond due internet connection issues. The feedback is a voice prompt or an error screen depending on the user action. + + * **Alexa app assets—** The sample app can show Alexa logos (assets) on the setup screen and display cards instead of showing placeholder assets. + + * **Comms UI improvements—** Updated the contacts uploading logic in the `Comms UI` AACS app component to ensure the sample app only uploads the contacts for the primary phone. + +* Updated the AACS Telephony library to get the outgoing phone account using the Android standard API `getDefaultOutgoingPhoneAccount`. AACS Telephony no longer sends an account query intent when receiving the `PhoneCallController.Dial` message from the Auto SDK Engine. + +* Added a new intent `com.amazon.aacstelephony.bluetooth.connectionCheckCompleted`, which AACS Telephony service broadcasts when it finishes the initial bluetooth connection check. + +* Updated the `alexa-auto-lwa-auth` app component to use the `Authorization` Auto SDK interface for CBL authorization. + +### Other changes + +* Moved several source code directories within the `aac-sdk` root directory to support the enhanced build system. + + * Removed `aac-sdk/platforms/android/`. The deprecated Java platform interfaces and JNI are in their respective modules. For example, the Alexa module Java interfaces and JNI are moved from `aac-sdk/platforms/android/modules/alexa/` to `aac-sdk/modules/alexa/android/` + + * Removed `aac-sdk/extensions/aasb/` because using AASB messages with MessageBroker is the primary Auto SDK API. AASB code for each module is in the respective module directory. For example, the AASB code for the Alexa module is in `aac-sdk/modules/alexa/aasb/`. Note that the AASB message headers to include in your application are not in this directory since they are generated as part of the Auto SDK build output. + + * Moved `aac-sdk/extensions/system-audio/` to `aac-sdk/modules/system-audio/` + + * Moved `aac-sdk/extensions/bluetooth/` to `aac-sdk/modules/bluetooth/` + + * Moved `aac-sdk/extensions/loopback-detector/` to `aac-sdk/modules/loopback-detector/` + + * Moved `aac-sdk/platforms/android/alexa-auto-client-service/` to `aac-sdk/aacs/android/` + + * Moved `aac-sdk/platforms/android/alexa-auto-client-service/app-components/` to `aac-sdk/aacs/android/app-components/` + + * Moved `aac-sdk/samples/android-aacs-sample-app/` to `aac-sdk/aacs/android/sample-app/` + + * Moved `aac-sdk/platforms/android/alexa-auto-client-service` `/commonutils/` , `/ipc/`, and `/constants/` to `aac-sdk/aacs/android/common/` + + * Moved AACS media player files to a directory `audioOutput` within `aac-sdk/platforms/android/alexa-auto-client-service/service/` + + * Moved the Media App Command and Control Android library from `aac-sdk/platforms/android/maccandroid/` to `aac-sdk/aacs/android/service/modules/maccandroid/` + +* In the LVC extension, the `LocalSearchProvider` AASB messages now have topic `LocalNavigation`. For example, the existing message `LocalSearchProvider.SearchRequest` in 3.3 is `LocalNavigation.SearchRequest` in 4.0. The next major release version of Auto SDK will change the topic back to `LocalSearchProvider`. + +* Deprecated the option to build AACS as an APK. Starting from Auto SDK 4.0, you can only build AACS as an AAR. + +* Removed the Android sample app based on the Java platform interfaces. The AACS sample app demonstrates using Auto SDK on Android. + +### Resolved issues + +* Fixed an issue preventing the generic `DEFAULT` type `LocalMediaSource` from working in offline mode with LVC. + +* Fixed a race condition in `SpeechRecognizer` in which enabling wake word detection immediately after calling `startCapture()` resulted in a missing call to `stopAudioInput()` when wake word detection was later disabled. + +* Fixed a deadlock that could occur in an application that uses the deprecated `AuthProvider` interface and starts, stops, and restarts the Engine in quick succession. + +* Fixed an issue in which Spotify playback commands were delayed on QNX. + +* Fixed an issue in which the Engine added malformed `PhoneCallController` context to `PhoneCallController` events sent to Alexa. + +* Fixed an issue in which AACS did not acquire audio focus prior to playing Alexa speech. + +### Known issues + +**General** + +* If you do not specify the `deviceSettings.locales` field of the Alexa module configuration, the Engine automatically declares support for the following locale combinations: ["en-US", "es-US"], ["es-US", "en-US"], ["en-IN", "hi-IN"], ["hi-IN", "en-IN"], ["fr-CA", "en-CA"], ["en-CA", "fr-CA"]. + The Engine does not automatically declare support for default locale combinations if you assign an empty value to the `locales` field. + +* The Engine does not persist the `aace.alexa.wakewordEnabled` Engine property setting across device reboots. Your application has to persist the setting and set the property again at each Engine start. AACS implements persisting this property and hence does not have this issue. + +* If your Linux platform does not use AVX2 instructions, the Amazonlite wake word library initialization causes an illegal instruction error. + +* When using LVC and stopping the Engine, the `AlexaClient` connection status remains `CONNECTED` because the connection to LVC is not disabled. Your application should not accept user utterances while the Engine is stopped despite the connection status showing `CONNECTED`. + +* The [Alexa Automotive UX guidelines](https://developer.amazon.com/en-US/docs/alexa/alexa-auto/display-cards.html#dismiss-display-cards) specify when to automatically dismiss a `TemplateRuntime` display card for each template type. The Engine publishes the `TemplateRuntime` interface messages `ClearTemplate` and `ClearPlayerInfo` based on the timeouts configured in the `aace.alexa.templateRuntimeCapabilityAgent` Engine configuration. However, the configuration does not provide enough granularity to specify timeouts for different types of display cards. Consequently, there is no way for your application to configure automatically dismissing local search templates (e.g., `LocalSearchListTemplate2`) with a different timeout than other templates (e.g., `WeatherTemplate`). The configuration also does not provide a way for you to specify infinite timeout for `NowPlaying` cards. You must implement your application’s dismissal logic for display cards and media info accordingly. + +* When the user requests to view their list of timers on an APL-enabled application, they cannot use an utterance such as “Alexa, scroll up” to scroll through the list shown on the APL card. + +* There is a rare race condition in which publishing the `AlexaClient.StopForegroundActivity` message does not cancel the active Alexa interaction. The race condition can happen when the application publishes the message at the beginning of the `THINKING` state `AlexaClient.DialogStateChanged` transition. + +* On the Poky Linux 32-bit platform, the C++ sample app shuts down with an error on launch. + +* In offline mode with LVC, you might not see the `AlexaClient.DialogStateChanged` `THINKING` state transition if the user invokes Alexa with hold-to-talk and your application provides the audio input data in one large chunk. + +* In offline mode with LVC, Alexa gets stuck in the `THINKING` state and does not respond after changing the locale setting. The state recovers after a few minutes. + +* The `CBL` module uses a backoff when refreshing the access token after expiry. If the internet is disconnected when the Engine attempts the refresh, it might take up to a minute to refresh the token after the internet connection is restored. + +* Some `Core` module messages published by the Engine do not have a corresponding message for the application to report a handling failure. For example, if the user invokes Alexa by tap-to-talk, and the application cannot handle the `AudioInput.StartAudioInput` message, the Engine assumes the application handled the message properly and will provide audio data. As a result, the Engine state and application state might become out of sync. The affected messages are the following: + * `AudioInput`: + * `StartAudioInput` + * `AudioOutput`: + * `SetPosition` + * `VolumeChanged` + * `MutedStateChanged` + +**Car control** + +* If you configure the Auto SDK Engine and connect to Alexa using a set of endpoint configurations, you cannot delete any endpoint in the set from Alexa. For example, after you configure set A with endpoints 1, 2, and 3, if you change your car control configuration during development to set B with endpoints 2, 3, and 4, Alexa retains endpoint 1 from set A, which might interfere with resolving the correct endpoint ID for your utterances. However, any endpoint configurations with matching IDs override previous configurations. For example, the configuration of endpoint 2 in set B replaces endpoint 2 in set A. During development, limit configuration changes to create only supersets of previous endpoint configurations. Work with your Solutions Architect or Partner Manager to produce the correct configuration on the first try. + +**Communications** + +* Alexa does not understand DTMF utterances that include letters. For example, "press A" and "dial 3*#B" do not result in the correct DTMF directives. + +* The user might experience unexpected results by trying to dial or place calls in the following ways: + * Using utterances that include “double”, “triple”, “hundred”, or “thousand.” For example, calling a number such as 1-800-xxx-xxxx by saying “Alexa call one eight *double oh*...” + * Pressing special characters such has “#” or “*” by saying "Alexa press * #." + +* The user cannot accept or reject incoming Alexa-to-Alexa calls by voice while playing a skill with extended multi-turn dialogs, such as Jeopardy or Skyrim. + +**Entertainment** + +* If the user requests Alexa to read notifications while music is playing, they might hear the music play for a split second between the end of one notification and the start of the next. + +* When an external media player authorization is in progress during Engine shutdown, a rare race condition might cause the Engine to crash. + +* If your application cancels an Alexa interaction by sending the `AlexaClient.StopForegroundActivity` message to the Engine during music playback, the Engine might erroneously request your application to dismiss the` NowPlaying` media info by publishing the `TemplateRuntime.ClearPlayerInfo` message. Your application should not dismiss the media info in this scenario. + +* When using the `System Audio` module, Audible and Amazon music might not play correctly on i.MX8 boards. + +**Local search and navigation** + +* In offline mode with LVC, after the user requests a list of POIs with an utterance such as “Alexa, find a nearby Starbucks”, Alexa does not recognize followup requests such as "Alexa, select the first one" and does not display or read detailed information about the requested selection. + +**AACS** + +* If you do not use the default audio output implementation (i.e., your application handles `AudioOutput` AASB messages), your application will not receive the `AudioOutput.Stop` message if Alexa media is playing when AACS shuts down. As a workaround, your application can listen to `AASB.StopService` or adopt `AACSPinger` to listen to the `STOPPED` state of AACS and stop the media accordingly. + +**AACS Sample App** + +* The AACS Sample App does not show the language selection screen when the app is built with Preview Mode. + +* The AACS Sample App only shows the language selection screen if there is a language mismatch with the system language setting at the first app launch. + + ## v3.3.0 released on 2021-09-30 ### Enhancements -* Added the `DeviceUsage` platform interface to provide the Alexa application network usage data to the Auto SDK Engine. The Auto SDK Engine emits this data as a metric to Amazon if Auto SDK is built with the `Device Client Metrics` extension. For more information, see the Core module README for [C++](./modules/core/README.md#providing-network-usage-data-to-auto-sdk) or [Android](./platforms/android/modules/core/README.md#providing-network-usage-data-to-auto-sdk). +* Added the `DeviceUsage` platform interface to provide the Alexa application network usage data to the Auto SDK Engine. The Auto SDK Engine emits this data as a metric to Amazon if Auto SDK is built with the `Device Client Metrics` extension. For more information, see the Core module README for [C++](./modules/core/README.md#providing-network-usage-data-to-auto-sdk) or [Android](./aacs/android/app-components/alexa-auto-device-usage/README.md). * Extended the features of the `Local Navigation` module for the `Local Voice Control (LVC)` extension. The `LocalSearchProvider` platform interface now enables you to provide customers with offline navigation to street addresses, cities, and neighborhoods in addition to the existing support for local search and navigation to points of interest. See the Local Navigation module README for information about integrating the features. >**Note:** There are updates to the `LocalSearchProvider` APIs. See the [Migration Guide](./MIGRATION.md) for details. -* Added a new generic `DEFAULT` media source to the list of sources supported by the `LocalMediaSource` platform interface. The DEFAULT source can be used for voice playback control of any arbitrary media sources on the infotainment system outside of deep-linked MACC applications using the `ExternalMediaAdapter` interface and existing sources supported by name through the `LocalMediaSource` interface. For details about integrating a default media source, see the Alexa module README for [C++](./modules/alexa/README.md) or [Android](./platforms/android/modules/alexa/README.md). +* Added a new generic `DEFAULT` media source to the list of sources supported by the `LocalMediaSource` platform interface. The DEFAULT source can be used for voice playback control of any arbitrary media sources on the infotainment system outside of deep-linked MACC applications using the `ExternalMediaAdapter` interface and existing sources supported by name through the `LocalMediaSource` interface. For details about integrating a default media source, see the Alexa module README for [C++](./modules/alexa/README.md) or [Android](https://github.com/alexa/alexa-auto-sdk/blob/3.3/platforms/android/modules/alexa/README.md). * Added offline LVC support for tuning to station names on terrestrial radio and SiriusXM. E.g., “Play CNN on Sirius XM” and “Play KISS FM”. This feature is already available in online mode. * Enhancements for AACS: - * Added an app component called `alexa-auto-carcontrol` that deeply integrates Auto SDK car control features into the Android Automotive OS. For more information about AACS deep integration to Car Control, please refer to this [README](./platforms/android/app-components/alexa-auto-carcontrol/README.md). + * Added an app component called `alexa-auto-carcontrol` that deeply integrates Auto SDK car control features into the Android Automotive OS. For more information about AACS deep integration to Car Control, please refer to this [README](https://github.com/alexa/alexa-auto-sdk/blob/3.3/platforms/android/app-components/alexa-auto-carcontrol/README.md). * Added an enhancement in which AACS can automatically sync Alexa’s timezone and locale properties with the device system settings when you set the `syncSystemPropertyChange` field to true in your AACS configuration file. If you set the field to false or omit it, you still have flexibility to change the properties in your own implementation. @@ -174,7 +335,7 @@ Fixed an issue in which wake words cannot be detected correctly when using the ` ## v3.2.0 released on 2021-05-19 ### Enhancements -* Added the `DeviceSetup` platform interface that handles events and directives related to device setup during or after an out-of-the-box experience (OOBE). After the user login, Alexa is informed that device setup is complete and starts the on-boarding experience, for example, by starting a short first-time conversation. For more information, see the Alexa module README for [C++](./modules/alexa/README.md) or [Android](./platforms/android/modules/alexa/README.md). +* Added the `DeviceSetup` platform interface that handles events and directives related to device setup during or after an out-of-the-box experience (OOBE). After the user login, Alexa is informed that device setup is complete and starts the on-boarding experience, for example, by starting a short first-time conversation. For more information, see the Alexa module README for [C++](./modules/alexa/README.md) or [Android](https://github.com/alexa/alexa-auto-sdk/blob/3.3/platforms/android/modules/alexa/README.md). * Added support in the Connectivity module to provide the network identifier from the vehicle to Alexa, which enables automakers to offer full connectivity plans to customers. For connectivity status, the module supports sending the version of the terms and conditions through a field called `termsVersion`. Also, the `termsStatus` field accepts `DEFERRED`, which means Alexa can remind users to respond to the terms and conditions at a later time. @@ -197,7 +358,7 @@ Fixed an issue in which wake words cannot be detected correctly when using the ` * Enhancements for AACS: - * Added AACS instrumentation, which enables you to better understand the interactions between your application and AACS. Through instrumentation, you log Alexa Auto Service Bridge (AASB) messages to a file, which you can review for debugging purposes. For information about AACS instrumentation, see the [README](./platforms/android/alexa-auto-client-service/android-service/service/src/debug/java/com/amazon/alexaautoclientservice/README.md). + * Added AACS instrumentation, which enables you to better understand the interactions between your application and AACS. Through instrumentation, you log Alexa Auto Service Bridge (AASB) messages to a file, which you can review for debugging purposes. For information about AACS instrumentation, see the [README](./aacs/android/README.md). * Added an app component called `alexa-auto-telephony`, which enables you to pre-integrate Alexa Phone Call Controller functionalities with Android Telephony. @@ -205,7 +366,7 @@ Fixed an issue in which wake words cannot be detected correctly when using the ` * Added the AACS AAR, which you can include in your application. - * The timeout for AASB synchronous messages is now configurable. For information about configuring the timeout, see the [README](./platforms/android/alexa-auto-client-service/android-service/README.md#auto-sdk-modules). + * The timeout for AASB synchronous messages is now configurable. For information about configuring the timeout, see the [README](./aacs/android/service/README.md#auto-sdk-modules). * Enhancements for AACS Sample App: @@ -231,7 +392,7 @@ Fixed an issue in which wake words cannot be detected correctly when using the ` * Improved the Auto SDK Voice Chrome extension to allow the height and width of the linear voice chrome to be controlled by the parent layout. Previously, the dimensions were fixed. ### Resolved Issues -* Disabled APL by default in AACS to make sure utterances like "tell me a joke" work correctly without handling APL. If your platform wants to implement APL, see the AACS [Configuration README](./platforms/android/alexa-auto-client-service/android-service/README.md#aacs-module-enablement) to enable it. +* Disabled APL by default in AACS to make sure utterances like "tell me a joke" work correctly without handling APL. If your platform wants to implement APL, see the AACS [Configuration README](./aacs/android/service/README.md#aacs-module-enablement) to enable it. * An SMS message can be sent to an Alexa contact correctly. A user request to send an SMS message to an Alexa contact no longer results in an Alexa-to-Alexa message. @@ -322,7 +483,7 @@ Therefore, if the current device locale is different from the default locale, yo >**Note:** Offline search with the Local Navigation module is only supported in the en-US locale. -* Added the Alexa Auto Client Service (AACS) Sample App that demonstrates how an application uses AACS. The Auto SDK includes the app components used by the AACS Sample App, which you can also use when developing an application that communicates with AACS. For information about the AACS Sample App, see the [README](./samples/android-aacs-sample-app/alexa-auto-app/README.md). +* Added the Alexa Auto Client Service (AACS) Sample App that demonstrates how an application uses AACS. The Auto SDK includes the app components used by the AACS Sample App, which you can also use when developing an application that communicates with AACS. For information about the AACS Sample App, see the [README](./aacs/android/sample-app/README.md). * Added support for Digital Audio Broadcasting (DAB) radio. For more information about the DAB local media source, see the [Alexa module README](./modules/alexa/README.md). * Enhancements for AACS: @@ -331,13 +492,13 @@ Therefore, if the current device locale is different from the default locale, yo * Added support for the Android `ContentProvider` class, which is a standard Android mechanism for performing CRUD (Create, Read, Update, Delete) operations on stored data. By extending this class, you can use a content provider, instead of AACS messages, to manage Auto SDK properties and retrieve state information. - For information about how AACS uses `FileProvider` and `ContentProvider`, see the [README](./platforms/android/alexa-auto-client-service/README.md). + For information about how AACS uses `FileProvider` and `ContentProvider`, see the [README](./aacs/android/service/README.md). - * Added support for a `ping` broadcast to check the AACS connection state. For more information about how to use `ping`, see the [README](./platforms/android/alexa-auto-client-service/README.md). + * Added support for a `ping` broadcast to check the AACS connection state. For more information about how to use `ping`, see the [README](./aacs/android/service/README.md). - * Added support for caching AASB message intent targets based on AASB Action. This enables you to define an intent filter with a subset of the possible actions for an AASB topic. For more information on specifying intent targets, see the [README](./platforms/android/alexa-auto-client-service/README.md#specifying-the-intent-targets-for-handling-messages). + * Added support for caching AASB message intent targets based on AASB Action. This enables you to define an intent filter with a subset of the possible actions for an AASB topic. For more information on specifying intent targets, see the [README](./aacs/android/README.md#specifying-the-intent-targets-for-handling-messages). - * Added support for Text-to-Speech Service, which allows Android applications to interact with Android TTS APIs to convert text to speech. For information about the Text-to-Speech Service, see the [README](./platforms/android/alexa-auto-client-service/tts/README.md). + * Added support for Text-to-Speech Service, which allows Android applications to interact with Android TTS APIs to convert text to speech. For information about the Text-to-Speech Service, see the [README](./aacs/android/app-components/alexa-auto-tts/README.md). ### Resolved Issues @@ -407,7 +568,7 @@ Therefore, if the current device locale is different from the default locale, yo * `setPosition(int64_t position)` * `volumeChanged(float volume)` * `mutedStateChanged(MutedState state)` - * AACS enables APL by default, but it does not have a default implementation for APL. AACS expects the client application to handle the messages or directives from the Engine. If APL is not handled on the client side, utterances that trigger APL capabilities, such as "tell me a joke," fail. To disable APL, add the lines below to the AACS configuration file. See "Configuring the AASB Interface Handlers" in the [AASB README](./extensions/aasb/README.md) for more details. + * AACS enables APL by default, but it does not have a default implementation for APL. AACS expects the client application to handle the messages or directives from the Engine. If APL is not handled on the client side, utterances that trigger APL capabilities, such as "tell me a joke," fail. To disable APL, add the lines below to the AACS configuration [file](./aacs/android/sample-app/alexa-auto-app/src/main/assets/config/aacs_config.json). ~~~ "aasb.apl": { @@ -423,7 +584,7 @@ Starting with v3.1.0, the Local Voice Control (LVC) extension is no longer suppo ## v3.0.0 released on 2020-10-09 ### Enhancements -* Added Alexa Auto Client Service (AACS), which enables OEMs of Android-based devices to simplify the process of integrating the Auto SDK. For more information about AACS, see the AACS [README](./platforms/android/alexa-auto-client-service/README.md). +* Added Alexa Auto Client Service (AACS), which enables OEMs of Android-based devices to simplify the process of integrating the Auto SDK. For more information about AACS, see the AACS [README](https://github.com/alexa/alexa-auto-sdk/blob/3.0/platforms/android/alexa-auto-client-service/README.md). * Added support for removing local media sources at runtime, such as a USB drive or a Bluetooth device. Previously, if a user removed a USB drive and then requested to play music from the USB drive, the Auto SDK would attempt to play and not return an appropriate error message. This feature is enabled with an existing field in the `LocalMediaSource` platform interface state. For information about the platform interface state, see the `alexa` module [README](./modules/alexa/README.md). @@ -573,7 +734,7 @@ Starting with Auto SDK v3.0, we no longer support the Automotive Grade Linux (AG * Added a Car Control module to support online-only car control use cases without the optional Local Voice Control (LVC) extension. The Car Control module provides the car control functionality introduced in Auto SDK 2.0.0 but does not require the LVC extension. * Made various enhancements to the External Media Player (EMP) Adapter to improve EMP behavior and facilitate implementation of Alexa audio focus. * Introduced the Property Manager, a new platform interface that allows you to set and retrieve Engine property values and be notified of property value changes. -* Added support for setting the timezone of a vehicle. The [AlexaProperties.h](./modules/alexa/platform/include/AACE/Alexa/AlexaProperties.h) and [AlexaProperties.java](./platforms/android/modules/alexa/src/main/java/com/amazon/aace/alexa/AlexaProperties.java) files now include a `TIMEZONE` property setting that is registered with the Property Manager during initialization and which you can manage using the Property Manager platform interface. +* Added support for setting the timezone of a vehicle. The [AlexaProperties.h](./modules/alexa/platform/include/AACE/Alexa/AlexaProperties.h) and [AlexaProperties.java](./modules/alexa/android/src/main/java/com/amazon/aace/alexa/AlexaProperties.java) files now include a `TIMEZONE` property setting that is registered with the Property Manager during initialization and which you can manage using the Property Manager platform interface. * Added support for specifying a custom volume range for voice interactions in implementations that use the optional Local Voice Control (LVC) extension. * Separated the LVC language models into independent APKs rather than providing them directly in the LVC APK as was done in previous releases. One language model APK is provided for each supported locale (currently en-US, en-CA, and fr-CA). @@ -584,7 +745,7 @@ Starting with Auto SDK v3.0, we no longer support the Automotive Grade Linux (AG * Fixed an issue where the Engine might hang during shutdown if it was shut down while TTS was being played or read. * Fixed an issue where Auto SDK initialization failed at startup when applications using the optional LVC extension didn't register a NetworkInfoProvider platform interface. * Fixed an issue where building the Auto SDK with sensitive logging enabled was not working as expected. -* Added alerts error enums (`DELETED` and `SCHEDULED_FOR_LATER`) to the [`Alerts.h`](./modules/alexa/platform/include/AACE/Alexa/Alerts.h) and [`Alerts.java`](./platforms/android/modules/alexa/src/main/java/com/amazon/aace/alexa/Alerts.java) files. +* Added alerts error enums (`DELETED` and `SCHEDULED_FOR_LATER`) to the [`Alerts.h`](./modules/alexa/platform/include/AACE/Alexa/Alerts.h) and [`Alerts.java`](./modules/alexa/android/src/main/java/com/amazon/aace/alexa/Alerts.java) files. * With the exception of road regulation and maneuver events, the Alexa cloud no longer returns an `INVALID_REQUEST_EXCEPTION` or `INTERNAL_SERVICE_EXCEPTION` in response to navigation events sent by the Auto SDK. * Alexa now prompts or notifies the clients and rejects the ping packet when the user deregisters from the companion app. @@ -680,7 +841,7 @@ Starting with Auto SDK v3.0, we no longer support the Automotive Grade Linux (AG >**Note:** In order to make use of this functionality, you must register the Navigation platform interface for Geolocation support. * **Enhanced the builder scripts** to simplify the build process by removing unnecessary options and including the default components for different targets. For details see the [Builder README](builder/README.md). -* **Refactored the Java Native Interface (JNI) code** used for Android platform interfaces for more modular deployment. In place of a single AAR including all Auto SDK native libraries, the Alexa Auto SDK now generates multiple AARs (one per module). Please see the [builder README](./builder/README.md) and the [Android Sample App README](./samples/android/README.md) for details. +* **Refactored the Java Native Interface (JNI) code** used for Android platform interfaces for more modular deployment. In place of a single AAR including all Auto SDK native libraries, the Alexa Auto SDK now generates multiple AARs (one per module). Please see the [builder README](./builder/README.md) and the [Android Sample App README](https://github.com/alexa/alexa-auto-sdk/blob/2.0/samples/android/README.md) for details. ### Resolved Issues * Fixed an issue where music streaming from online music service providers continued to play when the user switched to a local media source. @@ -773,7 +934,7 @@ All known issues from v1.6.0. ### Enhancements * Added a C++ sample application to demonstrate use cases that the Alexa Auto SDK supports. Read more about the C++ Sample App [here](./samples/cpp/README.md). -* Released the code for the AGL Alexa Voice Agent, a binding for Automotive Grade Linux powered by Alexa Auto SDK v1.5. The software is shipped as a standard AGL binding that exposes an API for speech recognition using the Alexa Voice Service. Please refer to the [AGL Alexa Voice Agent documentation](./platforms/agl/alexa-voiceagent-service/README.md) for instructions to build, install, and test the binding on an R-Car M3 board. +* Released the code for the AGL Alexa Voice Agent, a binding for Automotive Grade Linux powered by Alexa Auto SDK v1.5. The software is shipped as a standard AGL binding that exposes an API for speech recognition using the Alexa Voice Service. Please refer to the [AGL Alexa Voice Agent documentation](https://github.com/alexa/alexa-auto-sdk/blob/1.5/platforms/agl/alexa-voiceagent-service/README.md) for instructions to build, install, and test the binding on an R-Car M3 board. * Added support for runtime selection of the AmazonLite wake word locale. The AmazonLite locale will automatically switch when the AVS locale is switched. * Added support for optionally logging and uploading Alexa Auto SDK metrics to the Amazon cloud. Voice request metrics, for example, include start and end timestamps of user and Alexa speech and UPL between the request and Alexa’s response. Please contact your SA or Partner Manager for details or to request this package for Android. * Added support for an optional platform interface `EqualizerController`. The Equalizer Controller enables Alexa voice control of device audio equalizer settings by making gain adjustments to three frequency bands (“BASS”, “MIDRANGE”, and/or “TREBLE”). @@ -847,9 +1008,9 @@ All known issues from v1.3.0. ### Enhancements * Android 8 and ARM v8a platform support. -* Making calls to contacts from a locally-paired mobile phone as long as the Alexa Auto SDK has a valid auth token. Read more about [Contact Uploader API](./modules/contact-uploader/README.md). +* Making calls to contacts from a locally-paired mobile phone as long as the Alexa Auto SDK has a valid auth token. Read more about [Contact Uploader API](https://github.com/alexa/alexa-auto-sdk/blob/1.3/modules/contact-uploader/README.md). * Redial, answer, terminate, and decline calls using voice. End users can also send dual-tone multi-frequency (DTMF) via voice to interact with Interactive Voice Responders (IVRs). Read more here [Phone Call Controller](./modules/phone-control/README.md). -* Switching to local media sources, generic controls and deep linking into 3rd party media applications compatible with the Amazon Media App Command and Control (MACC) specification using the External Media Player Interface 1.1. This allows customers to switch between a CD player, AM/FM player, and auxiliary input that is MACC-compliant. Read more here [Handling External Media Adapter with MACCAndroidClient](./platforms/android/modules/alexa/README.md). +* Switching to local media sources, generic controls and deep linking into 3rd party media applications compatible with the Amazon Media App Command and Control (MACC) specification using the External Media Player Interface 1.1. This allows customers to switch between a CD player, AM/FM player, and auxiliary input that is MACC-compliant. Read more here [Handling External Media Adapter with MACCAndroidClient](./modules/alexa/README.md). * Enhancement for 3rd party wake word engine to enable cloud based verification. * Provides a way to override Template Runtime display card timeout values for RenderTemplate and RenderPlayerInfo by updating the [templateRuntimeCapabilityAgent Engine configuration](https://alexa.github.io/alexa-auto-sdk/modules/core/#configuring-the-engine) values. @@ -973,7 +1134,7 @@ There are no known issues in this release. * The Engine doesn't immediately reconnect to AVS when the **`NetworkInfoProvider`** updates network status. * Some shared memory objects are not freed when the Engine object is disposed. -Sample App issues are documented in the [Sample App README](./samples/android/README.md). +Sample App issues are documented in the [Sample App README](https://github.com/alexa/alexa-auto-sdk/blob/1.0/samples/android/README.md). ## v1.0.0 Beta released on 2018-04-29: diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 4ce7e3a91..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,52 +0,0 @@ -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - -# Detect the version number -execute_process( - COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/builder/scripts/gen-version.sh" -b - OUTPUT_VARIABLE SDK_BASE_VERSION -) - -project(AAC VERSION ${SDK_BASE_VERSION}) - -message(STATUS "Alexa Auto SDK - ${SDK_VERSION}") - -option(AAC_ENABLE_TESTS "Enable building test packages for AAC modules" ON) -if(AAC_ENABLE_TESTS) - enable_testing() -endif() - -if(AAC_ENABLE_COVERAGE) - message(STATUS "Enabling coverage for all modules.") - set(CMAKE_CXX_FLAGS "-g -O0 -Wall -fprofile-arcs -ftest-coverage") - set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE ON) -endif() - -if(MODULES) - set(CORE_MODULES ${MODULES}) - string(REPLACE "," " " CORE_MODULES ${CORE_MODULES}) - separate_arguments(CORE_MODULES) - foreach(MODULE ${CORE_MODULES}) - add_subdirectory(modules/${MODULE}) - endforeach() -else() - add_subdirectory(modules/address-book) - add_subdirectory(modules/alexa) - add_subdirectory(modules/apl) - add_subdirectory(modules/car-control) - add_subdirectory(modules/cbl) - add_subdirectory(modules/connectivity) - add_subdirectory(modules/core) - add_subdirectory(modules/messaging) - add_subdirectory(modules/navigation) - add_subdirectory(modules/phone-control) - add_subdirectory(modules/text-to-speech) - add_subdirectory(modules/text-to-speech-provider) -endif() - -if(EXTRA_MODULES) - string(REPLACE "," " " EXTRA_MODULES ${EXTRA_MODULES}) - separate_arguments(EXTRA_MODULES) - foreach(EXTRA_MODULE ${EXTRA_MODULES}) - add_subdirectory(${EXTRA_MODULE}) - endforeach() -endif() diff --git a/GETSTARTED.md b/GETSTARTED.md index eea6c2cda..39e32fee6 100644 --- a/GETSTARTED.md +++ b/GETSTARTED.md @@ -24,13 +24,13 @@ Follow these steps to get started with the Auto SDK: 4. Install the built package on your device as described in the builder [README](./builder/README.md). -5. Create and configure an instance of the Engine. For details, see the [C++](./modules/core/README.md#creating-the-engine) or [Android](./platforms/android/modules/core/README.md#creating-the-engine) Core module documentation. +5. Create and configure an instance of the Engine. For details, see the [Core module](./modules/core/README.md#creating-the-engine) documentation. 6. Extend the Auto SDK interfaces by creating a custom handler for each interface that you want to implement and registering the handler with the Engine. 7. Start the Engine using the `start()` command. -8. Use the Sample App ([C++](./samples/cpp/README.md) or [Android](./samples/android/README.md)) to see how the Auto SDK works and to test end-to-end functionality. +8. Use the Sample App ([C++](./samples/cpp/README.md) or [Android](./aacs/android/sample-app/README.md)) to see how the Auto SDK works and to test end-to-end functionality. ## Downloading Optional Extensions diff --git a/LICENSE b/LICENSE index d64569567..dec003497 100644 --- a/LICENSE +++ b/LICENSE @@ -1,202 +1,5 @@ +The contents of this repository are distributed under several different license agreements. Please refer to LICENSE file in the corresponding folder before using. - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ +If the license is not specified in the folder, the Apache 2.0 License applies. The Apache 2.0 license can be found at “./LICENSE_APACHE_V2”. - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - 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. +The resources under ./aacs/android/restrictedAssets are licensed under the Amazon Program Materials License Agreement (the “PMLA”). Please refer to ./aacs/android/restrictedAssets/LICENSE_PMLA file for more information. \ No newline at end of file diff --git a/LICENSE_APACHE_V2 b/LICENSE_APACHE_V2 new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/LICENSE_APACHE_V2 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/LINUX_INTEGRATION.md b/LINUX_INTEGRATION.md new file mode 100644 index 000000000..151b39a09 --- /dev/null +++ b/LINUX_INTEGRATION.md @@ -0,0 +1,95 @@ +# Auto SDK Integration Guide for Linux-based platforms + +The [Message Broker](./modules/core/README.md) API in Auto SDK provides a way for your application to interact with the Engine for a particular functionality, such as audio input, media streaming or location services. The Engine publishes messages when it needs to query data or delegate handling, such as rendering visual elements or placing a phone call to your custom implementation. Your application must publish messages to the Engine to provide a proactive notification of a state change or error. This loosely coupled MessageBroker API to subscribe to and publish messages allows you to have a lot more flexibility with how you design the application. + +The following architecture diagram illustrates a common design used for integrating the Auto SDK in Linux platforms. + +

+ +

+ + +To integrate your application with Auto SDK using the MessageBroker interface, follow these steps: + +## Creating the Engine + +To create an instance of the Engine, call the static function `aace::core::Engine::create()`: +``` +auto engine = aace::core::Engine::create(); +``` + +## Configuring the Engine + +Before you can start the Engine, you must configure it using the required `aace::core::config::EngineConfiguration` object(s) for the services you will be using: + +1. Generate the `EngineConfiguration` object(s). You can do this using a JSON configuration file, programmatically (using factory functions), or using a combination of both approaches. + + >**Note:** You can generate a single `EngineConfiguration` object that includes all configuration data for the services you will be using, or you can break the configuration data into logical sections and generate multiple `EngineConfiguration` objects. For example, you might generate one `EngineConfiguration` object for each module. Please refer to the respective module README for details. + +2. Call the Engine's `configure()` function, passing in the `EngineConfiguration` object(s): + + * For a single `EngineConfiguration` object, use: + ``` + engine->configure( config ); + ``` + + * For multiple `EngineConfiguration` objects, use: + ``` + engine->configure( { xConfig, yConfig, zConfig, ... } ); + ``` + + replacing `xConfig, yConfig, zConfig` with logical names to identify the `EngineConfiguration` objects you generated; for example: `coreConfig, alexaConfig, navigationConfig` + + >**Note**: You can call the Engine's `configure()` function only once, and you must call it before you subscribe to any messages or start the Engine. + +## Subscribing to messages from Engine + +1. Get a reference to the message broker from the Engine. + + ``` + auto messageBroker = engine->getMessageBroker(); + ``` +2. Use the following MessageBroker `subscribe()` function, passing in a message handler (a function that will handle the messages published by the Engine), the topic and action for which you want to receive messages from the Engine. + + ``` + void subscribe(MessageHandler handler, const std::string& topic = "", const std::string& action = ""); + ``` + >**Note**: If no topic or action is specified, then the application will receive messages for all topics and all actions. + +## Publishing messages to Engine + +Messages are published to the Engine to provide a proactive notification of a state change or an error. Use the MessageBroker `publish()` function to send a specific message to the Engine. + +``` +void publish(const std::string& message) +``` + +## Handling synchronous-style messages + +Most messages are either fire-and-forget, or they have a separate message that the application or Engine sends as an asynchronous response. However, some messages exchanged between the Engine and the application require a special reply message type. Typically these messages retrieve data that the requester requires "synchronously", such as application states retrieved for Alexa events. The Engine may either require a reply in response to a published message, or may send a reply to the application in response to a published message. + +### Replying to messages from the Engine + +Some messages that are sent to the application require a special `reply` message type to be sent back. In most cases the engine will block other messages from being sent until the reply is received (or until a timeout occurs), so it is important to send the reply message right away. To reply to a message: + +1. Set the `replyToId` in the reply message to the ID of the original message. + +2. Use the MessageBroker `publish()` function to send the reply. + +### Receiving reply messages from the Engine + +For some messages published by the application, the Engine may send a reply back to the application. In such cases, your application must subscribe to and handle the reply from the Engine. The `replyToId` in the reply message will contain the message ID for which the reply is sent. + +## Handling audio and stream based interface + +Stream based interfaces, such as AudioInput and AudioOutput, require the application to read from or write to a stream. For such messages, a stream ID is included in the message payload. + +1. Use the MessageBroker `openStream()` function to fetch the MessageStream corresponding to the stream ID. + +2. Specify the operation mode when opening the stream using the `MessageStream::Mode` enumeration. Streams can either be read-only, write-only, or support both input and output operations. + + ``` + std::shared_ptr openStream(const std::string& streamId, MessageStream::Mode mode) + ``` + + >**Note**: If a stream can not be opened for the specified operation, the openStream() call will fail and return a null object diff --git a/MIGRATION.md b/MIGRATION.md index 6723c0cd6..db7929371 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -7,6 +7,8 @@ This guide outlines the changes you need to make to migrate from Auto SDK v2.0 t ## Table of Contents +- [Migrating from Auto SDK v3.3.0 to v4.0.0](#migrating-from-auto-sdk-v330-to-v400) + - [Platform Interface Deprecation](#platform-interface-deprecation) - [Migrating from Auto SDK v3.2.1 to v3.3.0](#migrating-from-auto-sdk-v321-to-v330) - [Local Media Source and Global Preset Enhancements](#local-media-source-and-global-preset-enhancements) - [Migrating the Local Navigation Module APIs](#migrating-the-local-navigation-module-apis) @@ -34,6 +36,12 @@ This guide outlines the changes you need to make to migrate from Auto SDK v2.0 t - [Car Control Source File Relocation](#car-control-source-file-relocation) - [Code-Based-Linking (CBL) Handler in the Sample Apps](#code-based-linking-cbl-handler-in-the-sample-apps) +## Migrating from Auto SDK v3.3.0 to v4.0.0 +This section provides the information you need to migrate from Auto SDK v3.3.0 to Auto SDK v4.0.0 + +### Platform Interface Deprecation +The C++ and Java platform interfaces are deprecated in favor of Alexa Auto Services Bridge (AASB). Auto SDK 4.0 replaces the platform interfaces with a new `MessageBroker` API for subscribing to and publishing AASB messages. Details to migrate your application to the `MessageBroker` API are [here.](./MIGRATION_TO_AASB_MESSAGEBROKER.md) + ## Migrating from Auto SDK v3.2.1 to v3.3.0 This section provides the information you need to migrate from Auto SDK v3.2.1 to Auto SDK v3.3.0 @@ -171,7 +179,7 @@ The Engine notifies the application of any errors during the authorization proce * The `renderTemplate(const std::string& payload)` method has been removed. Use renderTemplate(const std::string& payload, FocusState focusState) instead. * The `renderPlayerInfo(const std::string& payload)` method has been removed. Use `renderPlayerInfo(const std::string& payload, PlayerActivity audioPlayerState, std::chrono::milliseconds offset, FocusState focusState)` instead. * In the Alexa module, `AlexaProperties::SUPPORTED_LOCALES` has been removed. For Alexa to recognize the locale setting, specify one of these values: de-DE, en-AU, en-CA, en-GB, en-IN, en-US, es-ES, es-MX, es-US, fr-CA, fr-FR, hi-IN, it-IT, ja-JP, pt-BR. -* `Engine::setProperty()` and `Engine::getProperty()` have been removed. Use `PropertyManager::setProperty()` and `PropertyManager::getProperty()` instead. For details about the Property Manager platform interface, see "Managing Runtime Properties with the Property Manager" ([for C++](./modules/core/README.md#managing-runtime-properties-with-the-property-manager) or [for Android](./platforms/android/modules/core/README.md#managing-runtime-properties-with-the-property-manager)). +* `Engine::setProperty()` and `Engine::getProperty()` have been removed. Use `PropertyManager::setProperty()` and `PropertyManager::getProperty()` instead. For details about the Property Manager platform interface, see "Managing Runtime Properties with the Property Manager" ([for C++](./modules/core/README.md#managing-runtime-properties-with-the-property-manager) or [for Android](https://github.com/alexa/alexa-auto-sdk/blob/3.0/platforms/android/modules/core/README.md#managing-runtime-properties-with-the-property-manager)). * The `SpeechRecognizer::enableWakeWordDetection()`, `SpeechRecognizer::disableWakeWordDetection()`, and `SpeechRecognizer::isWakewordDetectionEnabled()` methods have been removed. * The Contact Uploader module has been removed. Use the [Address Book module](#using-the-address-book-module) instead. @@ -210,7 +218,7 @@ This section outlines the changes you will need to make to migrate from Auto SDK ### Car Control Enhancements and Breaking Changes -Read the updated Car Control module README (for [C++ platforms](./modules/car-control/README.md) or [Android](./platforms/android/modules/car-control/README.md)) to get a complete understanding of all supported features and the current format of the "aace.carControl" configuration schema. Read the updated API documentation for the `CarControlConfiguration` builder class (for [C++ platforms](./modules/car-control/platform/include/AACE/CarControl/CarControlConfiguration.h) or [Android](./platforms/android/modules/car-control/src/main/java/com/amazon/aace/carControl/CarControlConfiguration.java)) if you construct your configuration programmatically. The changes to the "aace.carControl" configuration for v2.3 are backward-compatible, meaning your previous configuration (regardless of whether it was file-based or built programmatically with the `CarControlConfiguration` class) will still compile and produce a valid configuration to input to Auto SDK. However, several updates are recommended to ensure expected behavior, even if you do not want new features. +Read the updated Car Control module README (for [C++ platforms](./modules/car-control/README.md) or [Android](https://github.com/alexa/alexa-auto-sdk/blob/2.3/platforms/android/modules/car-control/README.md)) to get a complete understanding of all supported features and the current format of the "aace.carControl" configuration schema. Read the updated API documentation for the `CarControlConfiguration` builder class (for [C++ platforms](./modules/car-control/platform/include/AACE/CarControl/CarControlConfiguration.h) or [Android](./modules/car-control/android/src/main/java/com/amazon/aace/carControl/CarControlConfiguration.java)) if you construct your configuration programmatically. The changes to the "aace.carControl" configuration for v2.3 are backward-compatible, meaning your previous configuration (regardless of whether it was file-based or built programmatically with the `CarControlConfiguration` class) will still compile and produce a valid configuration to input to Auto SDK. However, several updates are recommended to ensure expected behavior, even if you do not want new features. #### 1. Zones configuration schema update @@ -402,7 +410,7 @@ This section outlines the changes you will need to make to migrate from Auto SDK ### Implementing the Property Manager Interface Auto SDK v2.2 introduces the Property Manager, a component that maintains runtime properties by storing property values and listeners and delegating the `setProperty()` and `getProperty()` calls from your application to the respective Engine services. The Engine invokes the PropertyManager platform interface method `propertyChanged()` to notify your application about property value changes originating internally. The property values may be set by Auto SDK modules that define constants (for example `FIRMWARE_VERSION` and `LOCALE`), or they may be initiated from the Alexa Voice Service (AVS), such as when the user changes the `TIMEZONE` setting in the Alexa Companion App. -`PropertyManager::setProperty()` and `PropertyManager::getProperty()` replace deprecated `Engine::setProperty()` and `Engine::getProperty()`. For details about the Property Manager platform interface, see "Managing Runtime Properties with the Property Manager" ([for C++](./modules/core/README.md#managing-runtime-properties-with-the-property-manager) or [for Android](./platforms/android/modules/core/README.md#managing-runtime-properties-with-the-property-manager)). +`PropertyManager::setProperty()` and `PropertyManager::getProperty()` replace deprecated `Engine::setProperty()` and `Engine::getProperty()`. For details about the Property Manager platform interface, see "Managing Runtime Properties with the Property Manager" ([for C++](./modules/core/README.md#managing-runtime-properties-with-the-property-manager) or [for Android](https://github.com/alexa/alexa-auto-sdk/blob/2.2/platforms/android/modules/core/README.md#managing-runtime-properties-with-the-property-manager)). ### Car Control Changes This section documents the changes you will need to make to migrate your Car Control implementation to Auto SDK v2.2. @@ -445,11 +453,11 @@ The following build changes have been introduced in Auto SDK v2.1: See the [Builder README](./builder/README.md#running-builder) for details about supported platforms and targets. -* For QNX targets, you must cross-compile with the QNX multimedia software for the system audio extension (which is built by default for QNX targets). This requires a QNX Multimedia Suite license. See the [System Audio extension README](./extensions/system-audio/README.md) for details. +* For QNX targets, you must cross-compile with the QNX multimedia software for the system audio extension (which is built by default for QNX targets). This requires a QNX Multimedia Suite license. See the [System Audio extension README](https://github.com/alexa/alexa-auto-sdk/blob/2.1/extensions/experimental/system-audio/README.md) for details. ### Engine Configuration File Updates -The AVS Device SDK portion of the Auto SDK Engine configuration (the `aace.alexa.avsDeviceSDK` node) has been updated. See the [`config.json.in`](./samples/cpp/assets/config.json.in) file for details. +The AVS Device SDK portion of the Auto SDK Engine configuration (the `aace.alexa.avsDeviceSDK` node) has been updated. See the [`config.json.in`](https://github.com/alexa/alexa-auto-sdk/blob/2.1/samples/cpp/assets/config.json.in) file for details. * The `"deviceInfo"` node includes two new elements: `"manufacturerName"` and `"description"`. * A path to the capabilities database is now required. Use the `"capabilitiesDelegate"` element to specify this path. @@ -462,7 +470,7 @@ The AVS Device SDK portion of the Auto SDK Engine configuration (the `aace.alexa Auto SDK v2.1 introduces additional navigation features that you can integrate in your application to enrich the user's experience: add/cancel a waypoint, show/navigate to a previous destination, turn and lane guidance, and map display control. Implementing these enhancements required deprecating the `setDestination()` interface in favor of the `startNavigation()` interface and adding several additional interfaces. -To migrate from Auto SDK v2.0 to Auto SDK v2.1, you must update your platform implementation to use the `startNavigation()` method instead of the `setDestination()` method, modify the payload for the `getNavigationState()` method, and implement the new navigation methods. This guide takes you through these steps. Please see the Navigation module README for [C++](./modules/navigation/README.md) or [Android](./platforms/android/modules/navigation/README.md) for additional information and resources. +To migrate from Auto SDK v2.0 to Auto SDK v2.1, you must update your platform implementation to use the `startNavigation()` method instead of the `setDestination()` method, modify the payload for the `getNavigationState()` method, and implement the new navigation methods. This guide takes you through these steps. Please see the Navigation module README for [C++](./modules/navigation/README.md) or [Android](https://github.com/alexa/alexa-auto-sdk/blob/2.1/platforms/android/modules/navigation/README.md) for additional information and resources. #### What's New @@ -751,7 +759,7 @@ void NavigationHandler::showPreviousWaypoints() { The Auto SDK now implements version 1.2 of the TemplateRuntime interface to handle display card templates. If you support TemplateRuntime in your implementation, you must update your implementation to support the new card types. -The TemplateRuntime interface remains the same, but the `LocalSearchListTemplate1` template has been deprecated in favor of the new `LocalSearchListTemplate2` template. In addition, two new templates (`TrafficDetailsTemplate` and `LocalSearchDetailTemplate1`), are now supported. The `TrafficDetailsTemplate` includes commute information to favorite destinations such as home or work. The `LocalSearchDetailTemplate1` template includes information about specific locations or information in response to users asking for details about locations presented in the `LocalSearchListTemplate2` template. For details about the TemplateRuntime interface, see the [Alexa Voice Service (AVS) documentation](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/templateruntime.html). For details about implementing TemplateRuntime in your Auto SDK implementation see the Alexa module README for [C++](./modules/alexa/README.md#handling-display-card-templates) or [Android](./platforms/android/modules/alexa/README.md#handling-display-card-templates). +The TemplateRuntime interface remains the same, but the `LocalSearchListTemplate1` template has been deprecated in favor of the new `LocalSearchListTemplate2` template. In addition, two new templates (`TrafficDetailsTemplate` and `LocalSearchDetailTemplate1`), are now supported. The `TrafficDetailsTemplate` includes commute information to favorite destinations such as home or work. The `LocalSearchDetailTemplate1` template includes information about specific locations or information in response to users asking for details about locations presented in the `LocalSearchListTemplate2` template. For details about the TemplateRuntime interface, see the [Alexa Voice Service (AVS) documentation](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/templateruntime.html). For details about implementing TemplateRuntime in your Auto SDK implementation see the Alexa module README for [C++](./modules/alexa/README.md#handling-display-card-templates) or [Android](https://github.com/alexa/alexa-auto-sdk/tree/2.3/platforms/android/modules/alexa#handling-display-card-templates-). ### Car Control Source File Relocation @@ -761,7 +769,7 @@ The Car Control module platform interface files and documentation are now locate >**Note:** In addition, if you use custom assets for car control in an implementation with the optional Local Voice Control (LVC) extension, you must specify the path to the custom assets in both the Auto SDK car control configuration and the LVC configuration, not just the LVC configuration. For details, see [Path to Custom Car Control Assets for LVC Implementations](#path-to-custom-car-control-assets-for-lvc-implementations). ### Code-Based-Linking (CBL) Handler in the Sample Apps -Both of the Auto SDK Sample Apps now include the Code-Based Linking (CBL) handler implementation (in favor of the `AuthProvider` handler implementation ) to handle obtaining access tokens from Login with Amazon (LWA). Changing from the `AuthProvider` handler to the CBL handler is *not a required change*, but we recommend that you use the Auto SDK CBL interface for ease of implementation. For details about the CBL handler, please see the CBL module README [for C++](./modules/cbl/README.md) or [for Android](./platforms/android/modules/cbl/README.md). +Both of the Auto SDK Sample Apps now include the Code-Based Linking (CBL) handler implementation (in favor of the `AuthProvider` handler implementation ) to handle obtaining access tokens from Login with Amazon (LWA). Changing from the `AuthProvider` handler to the CBL handler is *not a required change*, but we recommend that you use the Auto SDK CBL interface for ease of implementation. For details about the CBL handler, please see the CBL module README [for C++](./modules/cbl/README.md) or [for Android](https://github.com/alexa/alexa-auto-sdk/blob/2.3/platforms/android/modules/cbl/README.md). If you want to continue using the `AuthProvider` interface, we recommend that you implement the new `onAuthFailure()` method that exposes 403 "unauthorized request" exceptions from Alexa Voice Service (AVS). This method may be invoked, for example, when your product makes a request to AVS using an access token obtained for a device which has been deregistered from the Alexa companion app. In the Sample Apps, you can override the interface and unset your login credentials as if the user had done so with your GUI interface: diff --git a/MIGRATION_TO_AASB_MESSAGEBROKER.md b/MIGRATION_TO_AASB_MESSAGEBROKER.md new file mode 100644 index 000000000..9d6b6a24a --- /dev/null +++ b/MIGRATION_TO_AASB_MESSAGEBROKER.md @@ -0,0 +1,316 @@ +# Migration Guide to Use MessageBroker API + + +## Table of Contents + +- [Overview](#overview) +- [Application architecture](#application-architecture) +- [Migrating existing platform interface handlers](#migrating-existing-platform-interface-handlers) +- [Handling audio and stream based interfaces](#handling-audio-and-stream-based-interfaces) +- [Handling synchronous-style messages](#handling-synchronous-style-messages) +- [Migrating existing AASB platform interface handler implementation](#migrating-existing-aasb-platform-interface-handler-implementation) +- [Hybrid or incremental migration](#hybrid-or-incremental-migration) + + +## Overview +Auto SDK 4.0 introduces a new MessageBroker API for applications to subscribe to and publish AASB messages. This API replaces the existing platform interfaces that developers use to integrate platform-specific functionality such as audio, location, and Alexa capabilities. MessageBroker also replaces the [deprecated AASB interface](https://github.com/alexa/alexa-auto-sdk/blob/v3.3.0/extensions/aasb/modules/aasb/platform/include/AACE/AASB/AASB.h) used in previous Auto SDK versions. + +Developers integrating with Auto SDK for the first time should only use the MessageBroker API. Developers who upgrade to Auto SDK 4.0 (and plan to continue to upgrade beyond 4.0), should migrate their existing applications as soon as possible. The next major release of Auto SDK will remove the platform interface API without maintaining backward compatibility with older versions of the SDK. + +## Application architecture +In most cases, the interface changes in Auto SDK do not require modifying the architecture of the existing Auto SDK client application. The following diagram shows an application with a typical architecture based on Auto SDK 3.3 next to the same application using the Auto SDK 4.0 MessageBroker API: + +

+ +

+ +In the example above, the key difference is that rather than creating handlers that extend platform interfaces, the new implementation uses a loosely coupled MessageBroker API to subscribe to and publish messages. It is straightforward to adapt the existing application handlers to MessageBroker by using a simple adapter pattern that does not require completely redesigning the application. + +## Migrating existing platform interface handlers + +The following diagram highlights the core differences between using the old platform interfaces and the new MessageBroker API. The left side shows the steps for creating the Engine and handlers and invoking interface methods in Auto SDK 3.3. The right side shows the equivalent steps using the MessageBroker API required for Auto SDK 4.0. + +

+ +

+ +Even though the MessageBroker API provides flexibility for how to design an application, it may be easier to adapt an existing implementation rather than redesigning it. + +The following example demonstrates how to modify a DoNotDisturb platform interface handler to use MessageBroker. + +**Example implementation of a DoNotDisturb handler in Auto SDK 3.3:** + +In Auto SDK 3.3, the DoNotDisturb platform interface has the following methods: + +```c++ + /** + * Handle setting of DND directive. + * + * @param [in] doNotDisturb setting state + */ + virtual void setDoNotDisturb(const bool doNotDisturb) = 0; + + /** + * Notifies the Engine of a platform request to set the DND State + * + * @param [in] doNotDisturb setting state + * @return true if successful, false if change was rejected + */ + bool doNotDisturbChanged(const bool doNotDisturb); + +``` + +The implementation overrides the `setDoNotDisturb()` platform interface method to provide application-specific behavior (in this case, logging a message to the console) and calls the Engine interface method `doNotDisturbChanged` to request a change to the DoNotDisturb setting. + +```c++ +#include + +class DoNotDisturbHandler : public DoNotDisturb { + public: + DoNotDisturbHandler() = default; + void setDoNotDisturb(bool doNotDisturb) override; + void notifyDoNotDisturbSettingChange(bool doNotDisturb); +}; + + +void DoNotDisturbHandler::setDoNotDisturb(bool doNotDisturb) { + std::cout << "setDoNotDisturb: " << doNotDisturb << std::endl; +} + +void DoNotDisturbHandler::notifyDoNotDisturbSettingChange(bool doNotDisturb) { + // Notify the Engine of a request to change the DND setting by calling + // the Engine interface method implemented in the DoNotDisturb base class + doNotDisturbChanged(bool doNotDisturb); +} + +``` + +**Example implementation of a DoNotDisturb handler in Auto SDK 4.0:** + +In Auto SDK 4.0 the [SetDoNotDisturbMessage](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/alexa/aasb-docs/DoNotDisturb/index.html#setdonotdisturb) and the [DoNotDisturbChangedMessage](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/alexa/aasb-docs/DoNotDisturb/index.html#donotdisturbchanged) replace `setDoNotDisturb` the `doNotDisturbChanged` methods, respectively. + +The following example shows the same core logic in the handler, but it uses the MessageBroker API instead of extending a platform interface. + +```c++ +#include +#include +#include + +class DoNotDisturbHandler { + public: + DoNotDisturbHandler(std::shared_ptr messageBroker); + void setDoNotDisturb(bool doNotDisturb); + void doNotDisturbChanged(bool doNotDisturb); + private: + std::shared_ptr m_messageBroker; +}; + + +DoNotDisturbHandler::DoNotDisturbHandler( + std::shared_ptr messageBroker) : + m_messageBroker(messageBroker) { + + // subscribe to the "SetDoNotDisturb" message + m_messageBroker->subscribe( + [=](const std::string& msg) { + SetDoNotDisturbMessage _msg = json::parse(msg); + setDoNotDisturb(_msg.payload.doNotDisturb); + }, + SetDoNotDisturbMessage::topic(), + SetDoNotDisturbMessage::action()); +} + +void DoNotDisturbHandler::setDoNotDisturb(bool doNotDisturb) { + std::cout << "setDoNotDisturb: " << doNotDisturb << std::endl; +} + +void DoNotDisturbHandler::notifyDoNotDisturbSettingChange(bool doNotDisturb) { + // Notify the Engine of a request to change the DND setting by publishing + // a "DoNotDisturbChanged" message + DoNotDisturbChangedMessage _msg; + _msg.payload.doNotDisturb = doNotDisturb; + m_messageBroker->publish(_msg.toString()); // publish is fire and forget +} + +``` +A reference to the MessageBroker is required. This can be accessed from the Engine object and provided when creating the DoNotDisturbHandler instance in the main application code: + +```c++ +auto handler = std::make_shared(engine->getMessageBroker()); +``` + +## Handling audio and stream based interfaces + +Auto SDK 4.0 replaces audio stream platform interfaces `AudioInput` and `AudioOutput` with the MessageBroker's `MessageStream` API and corresponding AASB messages with "AudioInput" and "AudioOutput" topics. When the application receives a message that requires it to read from or write to a stream, the message payload includes a stream ID. The application uses the stream ID to “open” the stream for I/O. Developers with existing handlers for media players or microphone, for example, should migrate their handlers to use the new MessageBroker and MessageStream API. + +>**Note** In previous versions of Auto SDK, the Engine "opened" audio channels through the `AudioInputProvider` and `AudioOutputProvider` platform interfaces prior to requesting audio input or output through the `AudioInput` and `AudioOutput` platform interface instances representing each channel. In Auto SDK 4.0, there is no AASB message equivalent of `AudioInputProvider` or `AudioOutputProvider`. When the Engine needs audio input from a particular channel, it sends the `AudioInput.StartAudioInput` message with the channel type specified in the payload. Similarly, when the Engine needs to play audio for a particular channel, it sends the `AudioOutput.Prepare` message with the channel type specified in the payload. + +The following example demonstrates how the application would open an input stream after receiving the `StartAudioInput` message, and write data to the stream until a `StopAudioInput` message is received: + +```c++ +#include +#include + +// subscribe to the StartAudioInput message +messageBroker->subscribe([=](const std::string& msg) { + // parse the json message + StartAudioInputMessage _msg = json::parse(msg); + // open the stream for writing + auto streamId = _msg.payload.streamId; + auto stream = messageBroker->openStream( + streamId, + MessageStream::Mode::WRITE); + startAudioInput(streamId, stream) + }), + StartAudioInputMessage::topic(), + StartAudioInputMessage::action()); + +// subscribe to the StopAudioInput message +messageBroker->subscribe([=](const std::string& msg) { + // parse the json message + StopAudioInputMessage _msg = json::parse(msg); + auto streamId = _msg.payload.streamId; + stopAudioInput(streamId); + }), + StopAudioInputMessage::topic(), + StopAudioInputMessage::action()); + + +void startAudioInput(const std::string& streamId, std::shared_ptr stream) { + // On another thread, write data to the stream until + // you receive a StopAudioInput message with the same streamId + // ... + // Return quickly to avoid blocking the MessageBroker's outgoing thread! +} + +void stopAudioInput(const std::string& streamId) { + // Stop writing audio data to the stream + // ... + // Return quickly to avoid blocking the MessageBroker's outgoing thread! +} + +``` + +A MessageStream can be read-only, write-only, or support both read and write operations. It is required to specify the operation mode when opening the stream using the `MessageStream::Mode` enumeration. If the MessageBroker cannot open a stream for the specified operation, the `openStream()` call will fail and return a null object. + + +## Handling synchronous-style messages + +Most AASB messages are either fire-and-forget, or they have a separate message that the application or Engine sends as an asynchronous response. However, some messages exchanged between the Engine and the application require a special `reply` message type. Typically these messages retrieve data that the requester requires "synchronously", such as application states retrieved for Alexa events. The Engine may either require a reply in response to a published message, or may send a reply to the application in response to a published message. + +### Replying to messages from the Engine + +In most cases in which a message requires a reply, the Engine will block sending other messages until it receives the reply (or until a timeout occurs), so it is important to send the reply message right away. + +The following example demonstrates how to subscribe to the GetLocation message from the LocationProvider interface and send a reply back to the Engine: + +```c++ +#include + +// subscribe to GetLocation message +m_messageBroker->subscribe([=](const std::string& msg) { + GetLocationMessageReply _reply; + // set the reply message "replyToId" to the id of the + // original message: + _reply.header.messageDescription.replyToId = _msg.header.id; + // populate the reply message payload data + _reply.payload.location.latitude = m_latitude; + _reply.payload.location.longitude = m_longitude; + // publish ther reply + m_messageBroker->publish(_reply.toString()); + + }, + GetLocationMessage::topic(), + GetLocationMessage::action()); + +``` + +### Receiving reply messages from the Engine +For some messages published by the application, the Engine may send a `reply` back to the application. In such cases, your application must subscribe to and handle the reply from the Engine. The "replyToId" in the reply message will contain the message ID for which the reply is sent. + +The following example demonstrates how subscribe to `GetPropertyReply` message from the Engine. + +```c++ +m_messageBroker->subscribe( + [=](const std::string& message) { handleGetPropertyReplyMessage(message); }, + GetPropertyMessage::topic(), + GetPropertyMessage::action()); + + +// Publish GetPropertyMessage +void publishGetProperty(const std::string& name) { + GetPropertyMessage msg; + msg.payload.name = name; + m_messageBroker->publish(msg.toString()); + // Engine sends the GetProperty message reply with the requested property + // The "replyToId" in the reply message will contain the ID of this published message +} + +void handleGetPropertyReplyMessage(const std::string& message) { + GetPropertyMessageReply msg = json::parse(message); + + // Get the property value from the reply and handle in the implementation + const std::string& propertyValue = msg.payload.value +} + +``` + +## Migrating existing AASB platform interface handler implementation + +Auto SDK 3.3 supports AASB as an optional extension and platform interface. Developers using the AASB platform interface need to migrate the AASB platform interface handler to use the new MessageBroker API instead. This can be accomplished by following a similar pattern as described in the sections above; however, use MessageBroker to subscribe to *ALL* messages in order to provide the same functionality as the existing AASB platform interface. + +```c++ +class AASBHandler { +public: + AASBHandler(std::shared_ptr messageBroker); + void messageReceived(const std::string& message); + // engine interface implementation + void publish(const std::string& message); + std::shared_ptr openStream( + const std::string& streamId, MessageStream::Mode mode); +private: + std::shared_ptr m_messageBroker; +}; + +AASBHandler::AASBHandler( + std::shared_ptr messageBroker) : + m_messageBroker(messageBroker) { + + // subscribe to ALL messages and bind to the messageReceived() function + // since it has the same method signature as the message handler + m_messageBroker->subscribe( + std::bind(&AASBHandler::messageReceived, this, std::placeholders::_1) + ); +} + +void AASBHandler::messageReceived(const std::string& message){ + // application logic for handling AASB messages + std::cout << message << std::endl; +} + +void AASBHandler::publish(const std::string& message){ + // invoke the MessageBroker publish method + m_messageBroker->publish(message); +} + +std::shared_ptr AASBHandler::openStream( + const std::string& streamId, + MessageStream::Mode mode){ + // invoke the MessageBroker openStream method + return m_messageBroker->openStream(mode); +} + +``` + +## Hybrid or incremental migration + +Although Amazon recommends migrating the entire application to MessageBroker when upgrading to Auto SDK 4.0, it is possible to use a hybrid implementation of platform interface handlers and MessageBroker until Auto SDK removes the platform interface API. New interfaces added in Auto SDK 4.0 are enabled to use the MessageBroker API by default. + +The following diagram illustrates the architecture for a hybrid application: + +

+ +

+ + + diff --git a/NOTICE b/NOTICE index bc2665ef9..462366d6f 100644 --- a/NOTICE +++ b/NOTICE @@ -1,27 +1,33 @@ Alexa Auto SDK -Copyright 2017-2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. +Copyright 2017-2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. ************************* ALEXA AUTO SDK COMPONENTS ************************* The following Alexa Auto SDK components are licensed under the Apache License, Version 2.0 (the "License"): +aacs/android/app-components +aacs/android/assets +aacs/android/common +aacs/android/sample-app +aacs/android/service builder -extensions/system-audio -extensions/loopback-detector +modules/aasb modules/address-book modules/alexa modules/apl +modules/bluetooth modules/car-control modules/cbl -modules/contact-uploader modules/core +modules/custom-domain +modules/loopback-detector modules/messaging modules/navigation modules/phone-control -platforms/android -samples/android -samples/android-aacs-sample-app +modules/system-audio +modules/text-to-speech +modules/text-to-speech-provider samples/cpp You may not use this file except in compliance with the License. A copy of diff --git a/README.md b/README.md index 5d51c1b49..e2d830750 100644 --- a/README.md +++ b/README.md @@ -1,125 +1,65 @@ # Overview of the Alexa Auto SDK -The Alexa Auto SDK contains essential client-side software required to integrate Alexa into the automobile. The Auto SDK provides libraries that connect to Alexa and expose C++ and Java interfaces for your vehicle software to implement the platform-specific behavior for audio input, media streaming, calling through a connected phone, turn-by-turn navigation, controlling vehicle features such as heaters and lights, and more. You can use the included sample applications, one for C++ and one for Android, to learn about the Auto SDK interfaces and to test interactions before integration. +The Alexa Auto SDK contains essential client-side software required to integrate Alexa into the automobile. The Auto SDK provides libraries that connect to Alexa and expose interfaces for your vehicle software to implement the platform-specific behavior for audio input, media streaming, calling through a connected phone, turn-by-turn navigation, controlling vehicle features such as heaters and lights, and more. You can use the included sample application to learn about the Auto SDK interfaces and to test interactions before integration. + +The contents of this repository are distributed under several different license agreements. Please refer to the [LICENSE](./LICENSE) file for the license terms applicable to the materials that you are using. ## Table of Contents - [Auto SDK Architecture](#auto-sdk-architecture) -- [Auto SDK Modules and Extensions](#auto-sdk-modules-and-extensions) -- [Alexa Auto Client Service (AACS)](#alexa-auto-client-service-aacs) +- [Getting Started](#getting-started) +- [Auto SDK Integration](#auto-sdk-integration) - [Security Best Practices](#security-best-practices) - [See Also](#see-also) ## Auto SDK Architecture -The following architecture diagram illustrates a common design used for integrating the Auto SDK into the vehicle software. - - -

- -The following sections describe the relationships among components in the architecture. - -### Auto SDK Engine -The Engine is a system of components that provide the runtime implementation of the Auto SDK. The main program of your application or background service creates an instance of the Engine and configures the instance, registers platform interface handlers, and manages its lifecycle. When started by the main program, the Engine maintains a connection to Alexa, manages runtime execution states, and provides the underlying implementation of the functionality of the platform interfaces. - -### Platform Interfaces -Platform interfaces are abstract interfaces provided by the Auto SDK for you to implement the platform-specific functionality of the Auto SDK integration. “Platform-specific functionality” refers to components of the integration that interact with the hardware, operating system, underlying software frameworks, or external libraries. Each platform interface defines an API for the application to interact with the Engine for a particular component, such as audio input or location services. The Engine invokes a registered platform interface “handler” when it needs to query data or delegate handling, such as rendering visual elements or placing a phone call, to your custom implementation. The handler invokes the Engine to provide a callback to a request from the Engine or provide a proactive notification of a state change. - -### Handlers -Bridging the Engine and other processes running in the head unit, a handler implements the functionality required by the platform interface it extends. The implementation of a handler may include using an event bus, platform-specific inter-process communication (IPC) mechanisms, direct implementations with system libraries, or deep integrations with existing applications. - -## Auto SDK Modules and Extensions -The Auto SDK is organized into logically related groups of functionality called “modules,” which enable you to select only the features you want to include in your integration. Each module includes “Platform” and “Engine” libraries. The Platform library includes the platform interfaces and configuration options required for a feature, and the Engine library augments the base functionality of the Engine with the underlying implementation of the feature. - ->**Note:** The libraries of each module are written in C++, but building the Auto SDK for an Android target enables an Android version of the modules that provide Java wrappers on the C++ interfaces for easier use. - -The following sections describe the modules included in the Auto SDK. Modules not downloadable with the Auto SDK from GitHub are available as extensions, which you can obtain with help from your Amazon Solutions Architect (SA) or Partner Manager. - -### Core Module - -The Core module (for [C++](./modules/core/README.md) or [Android](./platforms/android/modules/core/README.md)) provides the infrastructure for audio input and output, authorization, logging, location reporting, metrics, property management, network monitoring services, local storage, and vehicle information services. The infrastructure is necessary for any module that provides platform interfaces (for example, the Alexa module). +The Auto SDK is modular, with a system of components that provide the runtime implementation of the Auto SDK. Each module exposes interfaces to handle specific functionality such as audio input and output, authorization, media streaming, navigation and controlling vehicle features. Most of the modules are included in the Auto SDK. Modules not downloadable with the Auto SDK from GitHub are available as extensions, which you can obtain with help from your Amazon Solutions Architect (SA) or Partner Manager. See [here](./SDK_MODULES.md) for more information on Auto SDK modules and extensions. -### Alexa Module +## Getting Started -The Alexa module (for [C++](./modules/alexa/README.md) or [Android](./platforms/android/modules/alexa/README.md)) supports Alexa features such as speech input and output, authorization, volume control, media playback, equalizer control, template and state rendering, local media sources, alerts, notifications, and do not disturb. +### Prerequisites +Complete the following steps before you get started with the Auto SDK: -### Navigation Module +1. Register for an [Amazon Developer Account](https://developer.amazon.com/home.html) and [create an Alexa device and security profile](./NEED_HELP.md#registering-a-product-and-creating-a-security-profile) to use the Auto SDK. +2. Make sure that you meet the requirements for building the Auto SDK and understand the dependencies, as described in the SDK builder [README](./builder/README.md). -The Navigation module (for [C++](./modules/navigation/README.md) or [Android](./platforms/android/modules/navigation/README.md)) provides support for Alexa to interface with the onboard navigation system. +### Build Auto SDK +Follow these steps to get started with the Auto SDK: -### Phone Call Controller Module +1. Clone the `alexa-auto-sdk` repository into your project. +2. If you want to use the optional Auto SDK modules, download the modules from the locations listed below. + * [AmazonLite Wake Word extension](https://developer.amazon.com/alexa/console/avs/preview/resources/details/Auto%20SDK%20Amazonlite%20Extension) -The Phone Call Controller module (for [C++](./modules/phone-control/README.md) or [Android](./platforms/android/modules/phonecontrol/README.md)) provides support for Alexa to interface with the onboard telephony system. + * [Alexa Communications extension](https://developer.amazon.com/alexa/console/avs/preview/resources/details/Auto%20SDK%20Alexa%20Comms%20Extension) -### Address Book Module + * [Local Voice Control extension](https://developer.amazon.com/alexa/console/avs/preview/resources/details/Auto%20SDK%20Local%20Voice%20Control%20Extension) -The Address Book module (for [C++](./modules/address-book/README.md) or [Android](./platforms/android/modules/addressbook/README.md)) augments the communications and navigation capabilities of Alexa with user data such as phone contacts and navigation favorites ("home", "work", etc.). + * [Device Client Metrics (DCM) extension](https://developer.amazon.com/alexa/console/avs/preview/resources/details/Auto%20SDK%20Metric%20Upload%20Service%20Extension) -### Code-Based Linking (CBL) Module + * [Voice Chrome for Android extension](https://developer.amazon.com/alexa/console/avs/preview/resources/details/Auto%20SDK%20Voice%20Chrome%20Extension) -The CBL module (for [C++](./modules/cbl/README.md) or [Android](./platforms/android/modules/cbl/README.md)) implements the CBL mechanism of acquiring Login with Amazon (LWA) access tokens. For information about the CBL mechanism, see the [Code-Based Linking documentation](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/authorize-cbl.html). + >The version of the optional extension archive must match the version of the Auto SDK that you are using. For example, if you are using Auto SDK 3.0 and want to install the Local Voice Control extension, you must download version 3.0 of the Local Voice Control extension archive. -### Alexa Presentation Language (APL) Module -The APL module (for [C++](./modules/apl/README.md) or [Android](./platforms/android/modules/apl/README.md)) enables devices to support a visual Alexa experience. + >**Note:** The Alexa Presentation Language (APL) module is provided publicly, but requires [additional packages](https://developer.amazon.com/alexa/console/avs/preview/resources/details/Alexa%20Auto%20SDK%20Alexa%20Presentation%20Language%20module) to be downloaded to successfully build. + +3. Build the Auto SDK as described in the builder [README](./builder/README.md). + +The following section provides the details of integrating with Android and Linux based platforms: ->**Note:** The [APL Render module](./platforms/android/modules/apl-render/README.md) is provided to enable APL rendering capabilities in an Android application. +## Auto SDK Integration -### Messaging Module -The Messaging module (for [C++](./modules/messaging/README.md) or [Android](./platforms/android/modules/messaging/README.md)) provides support for Short Message Service (SMS) capabilities of Alexa such as sending and reading text messages. +### Integrating Auto SDK in Android-based platforms -### Car Control Module -The Car Control module (for [C++](./modules/car-control/README.md) or [Android](./platforms/android/modules/car-control/README.md)) enables your application to build a custom vehicle-control experience that allows the user to voice-control vehicle features using Alexa. +The Alexa Auto Client Service (AACS) simplifies the process of integrating the Auto SDK in Android-based devices. AACS is an Alexa Auto SDK feature packaged in a stand alone Android application package (APK) or in an Android archive library (AAR). After you install, configure, and initialize AACS, it communicates with the applications, providing an interface between the applications and various Alexa functions, such as navigation and car control. You can also include AACS as an Android archive (AAR) in the application if you do not want to run AACS as a separate app. -### Connectivity Module -The Connectivity module (for [C++](./modules/connectivity/README.md) or [Android](./platforms/android/modules/connectivity/README.md)) creates a lower data consumption mode for Alexa, allowing automakers to offer tiered functionality based on the status of their connectivity plans. +[Learn more >>](./aacs/android/README.md) -### Text To Speech (TTS) Module -The TTS module (for [C++](./modules/text-to-speech/README.md) or [Android](./platforms/android/modules/text-to-speech/README.md)) enables a platform implementation to request synthesis of Alexa speech on demand from a text or Speech Synthesis Markup Language (SSML) string. +### Integrating Auto SDK in Linux-based platforms -### Text To Speech (TTS) Provider Module -The TTS provider module (for [C++](./modules/text-to-speech-provider/README.md) or [Android](./platforms/android/modules/text-to-speech-provider/README.md)) synthesizes Alexa speech on demand. This module requires Auto SDK to be built with the Local Voice Control extension. - -### AmazonLite Wake Word Extension -Wake Word enables hands-free, voice-initiated interactions with Alexa. The Wake Word extension enables AmazonLite Wake Word support in the Auto SDK. +The Alexa Auto Service Bridge (AASB) simplifies the process of integrating the Auto SDK in Linux-based devices. AASB framework provides a Message Broker API that transmits JSON messages between the OEM application and the Auto SDK. This API can be used publish and subscribe to AASB messages to implement the platform-specific functionality of the Auto SDK integration. -### Alexa Communications Extension -The Alexa Communications extension enables integration with Alexa-to-Alexa calling, Alexa-to-PSTN calling, and messaging capabilities. - -### Alexa Custom Assistant Extension -The Alexa Custom Assistant extension provides the functionality for toggling the settings of Alexa and the automaker's voice assistant, and notifies the IVI system at runtime about updates to the acting assistant for a specific interaction. - -### Bluetooth Extension -The Bluetooth extension allows the Auto SDK to connect to devices through the Bluetooth Classic or Bluetooth Low Energy (BLE) protocol. Using these protocols, the Auto SDK can offer Bluetooth-based features to users of Android or iOS smartphones. - -### Device Client Metrics (DCM) Extension -The Device Client Metrics (DCM) extension enables logging and uploading Auto SDK metrics to the Amazon cloud. Voice request metrics, for example, include start and end timestamps of user and Alexa speech and user perceived latency (UPL) between the request and Alexa’s response. - -### Geolocation Extension -The Geolocation extension adds geolocation consent support to the Auto SDK, enabling the user to grant consent to location sharing with Alexa from your application. - -### Local Voice Control (LVC) Extension -The LVC extension provides car control, communication, navigation, local search, and entertainment functionality, without an internet connection. It includes components that run an Alexa endpoint inside the vehicle's head unit. -#### Local Voice Control Module -The Local Voice Control module adds core functionality to Auto SDK to enable offline features. The module infrastructure bridges the Auto SDK Engine to the offline Alexa endpoint running in the head unit and is necessary for all other modules in the LVC extension. -#### Local Skill Service Module -The Local Skill Service module provides a multipurpose service to the Auto SDK Engine that enables components running alongside the offline Alexa endpoint to communicate with the Auto SDK Engine. The module infrastructure is necessary for other modules in the LVC extension. -#### Local Navigation Module -The Local Navigation module enables you to provide customers with offline Alexa local search and navigation to points of interest (i.e., categories, chains, and entities) and addresses. -#### Address Book Local Service Module -The Address Book Local Service module works with the Address Book module and the Local Skill Service module to augment the offline communications and navigation capabilities of Alexa with user data such as phone contacts and navigation favorites. -#### Car Control Local Service Module -The Car Control Local Service module works with the Car Control module and the Local Skill Service module to enable users to control vehicle features offline with Alexa. - -### Mobile Authorization Extension -The Mobile Authorization extension enables applications running on the vehicle's head unit to simplify the login experience. To log in to Alexa, the user uses the Alexa mobile app on a paired smartphone instead of opening a web browser and entering a code. - -### Voice Chrome for Android Extension -The Voice Chrome extension adds Voice Chrome support to the Auto SDK for Android x86 64-bit and Android ARM 32/64-bit platforms. Voice Chrome provides a consistent set of visual cues representing Alexa attention state across a range of Alexa-enabled devices. The Voice Chrome extension includes a prebuilt Android AAR library for easy integration with your applications, as well as a patch to the Android Sample App that adds the Voice Chrome functionality. - -## Alexa Auto Client Service (AACS) -AACS simplifies the process of integrating the Auto SDK in Android-based devices. After you install, configure, and initialize AACS, it communicates with the applications, providing an interface between the applications and various Alexa functions, such as navigation and car control. You can also include AACS as an Android archive (AAR) in the application if you don't want to run AACS as a separate app. For more information about AACS, see the AACS [README](./platforms/android/alexa-auto-client-service/README.md). - -AACS requires the Alexa Auto Service Bridge (AASB) extension, which provides a message-based interface to the Auto SDK Engine. For more information about AASB, see the [AASB README](./extensions/aasb/README.md). +[Learn more >>](./LINUX_INTEGRATION.md) ## Security Best Practices @@ -135,11 +75,7 @@ All Alexa products are required to follow the [Security Best Practices for Alexa The following documents or websites provide more information about the Auto SDK. * [In-vehicle Alexa experience design guidelines](https://developer.amazon.com/en-US/docs/alexa/alexa-auto/about-this-guide.html) include principles, voice, visual, user interface (UI) patterns, and multimodal best practices. -* [Getting Started Guide](./GETSTARTED.md) provides steps for getting started with the Auto SDK and for downloading extensions. * [Change Log](./CHANGELOG.md) provides a summary of feature enhancements, updates, and resolved and known issues. -* [Android Sample App](./samples/android/README.md) and [C++ Sample App](./samples/cpp/README.md) READMEs provide release notes about the sample apps. -* For Auto SDK API documentation, see the interface reference documentation: - * [Alexa Auto SDK for Android](https://alexa.github.io/alexa-auto-sdk/docs/android/) - * [Alexa Auto SDK for C++](https://alexa.github.io/alexa-auto-sdk/docs/cpp/) +* AASB message definition provides the reference documentation for AASB messages. You can find AASB message definition for each module [here.](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/index.html) by navigating to "Modules" tab and select a module on the left menu. For example, you can find AASB message definition for Address Book module [here.](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/address-book/aasb-docs/AddressBook/index.html) +* [AACS Sample App](./aacs/android/README.md) and [C++ Sample App](./samples/cpp/README.md) READMEs provide information about the sample apps. This helps you test interactions before integration. * [Migration Guide](./MIGRATION.md) describes how to migrate from one Auto SDK version to another. - diff --git a/SDK_MODULES.md b/SDK_MODULES.md new file mode 100644 index 000000000..fbf356669 --- /dev/null +++ b/SDK_MODULES.md @@ -0,0 +1,86 @@ +# Auto SDK Modules and Extensions +The Auto SDK is organized into logically related groups of functionality called “modules,” which enable you to select only the features you want to include in your integration. Each module includes "AASB", “Platform” and “Engine” libraries. The AASB library includes the AASB messages supported for the module, the Platform library includes the configuration options required for a feature, and the Engine library augments the base functionality of the Engine with the underlying implementation of the feature. + +## Core Module + +The Core module (see [README](./modules/core/README.md)) provides the infrastructure for audio input and output, authorization, logging, location reporting, metrics, property management, network monitoring services, local storage, and vehicle information services. The infrastructure is necessary for any module that uses the messaging interfaces (for example, the Alexa module). + +## Alexa Module + +The Alexa module (see [README](./modules/alexa/README.md)) supports Alexa features such as speech input and output, authorization, volume control, media playback, equalizer control, template and state rendering, local media sources, alerts, notifications, and do not disturb. + +## Navigation Module + +The Navigation module (see [README](./modules/navigation/README.md)) provides support for Alexa to interface with the onboard navigation system. + +## Phone Call Controller Module + +The Phone Call Controller module (see [README](./modules/phone-control/README.md)) provides support for Alexa to interface with the onboard telephony system. + +## Address Book Module + +The Address Book module (see [README](./modules/address-book/README.md)) augments the communications and navigation capabilities of Alexa with user data such as phone contacts and navigation favorites ("home", "work", etc.). + +## Code-Based Linking (CBL) Module + +The CBL module (see [README](./modules/cbl/README.md)) implements the CBL mechanism of acquiring Login with Amazon (LWA) access tokens. For information about the CBL mechanism, see the [Code-Based Linking documentation](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/authorize-cbl.html). + +## Alexa Presentation Language (APL) Module +The APL module (see [README](./modules/apl/README.md)) enables devices to support a visual Alexa experience. + +>**Note:** The [APL Render module](./aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/README.md) is provided to enable APL rendering capabilities in an Android application. + +## Messaging Module +The Messaging module (see [README](./modules/messaging/README.md)) provides support for Short Message Service (SMS) capabilities of Alexa such as sending and reading text messages. + +## Car Control Module +The Car Control module (see [README](./modules/car-control/README.md)) enables your application to build a custom vehicle-control experience that allows the user to voice-control vehicle features using Alexa. + +## Connectivity Module +The Connectivity module (see [README](./modules/connectivity/README.md)) creates a lower data consumption mode for Alexa, allowing automakers to offer tiered functionality based on the status of their connectivity plans. + +## Text To Speech (TTS) Module +The TTS module (see [README](./modules/text-to-speech/README.md)) enables a platform implementation to request synthesis of Alexa speech on demand from a text or Speech Synthesis Markup Language (SSML) string. + +## Text To Speech (TTS) Provider Module +The TTS provider module (see [README](./modules/text-to-speech-provider/README.md)) synthesizes Alexa speech on demand. This module requires Auto SDK to be built with the Local Voice Control extension. + +## Custom Domain Module +The Custom Domain module (see [README](./modules/custom-domain/README.md)) creates a bi-directional communication channel between the device and your custom cloud skills, allowing customized experience with the voice assistant. + +## AmazonLite Wake Word Extension +Wake Word enables hands-free, voice-initiated interactions with Alexa. The Wake Word extension enables AmazonLite Wake Word support in the Auto SDK. + +## Alexa Communications Extension +The Alexa Communications extension enables integration with Alexa-to-Alexa calling, Alexa-to-PSTN calling, and messaging capabilities. + +## Alexa Custom Assistant Extension +The Alexa Custom Assistant extension provides the functionality for toggling the settings of Alexa and the automaker's voice assistant, and notifies the IVI system at runtime about updates to the acting assistant for a specific interaction. + +## Bluetooth Extension +The Bluetooth extension allows the Auto SDK to connect to devices through the Bluetooth Classic or Bluetooth Low Energy (BLE) protocol. Using these protocols, the Auto SDK can offer Bluetooth-based features to users of Android or iOS smartphones. + +## Device Client Metrics (DCM) Extension +The Device Client Metrics (DCM) extension enables logging and uploading Auto SDK metrics to the Amazon cloud. Voice request metrics, for example, include start and end timestamps of user and Alexa speech and user perceived latency (UPL) between the request and Alexa’s response. + +## Geolocation Extension +The Geolocation extension adds geolocation consent support to the Auto SDK, enabling the user to grant consent to location sharing with Alexa from your application. + +## Local Voice Control (LVC) Extension +The LVC extension provides car control, communication, navigation, local search, and entertainment functionality, without an internet connection. It includes components that run an Alexa endpoint inside the vehicle's head unit. +### Local Voice Control Module +The Local Voice Control module adds core functionality to Auto SDK to enable offline features. The module infrastructure bridges the Auto SDK Engine to the offline Alexa endpoint running in the head unit and is necessary for all other modules in the LVC extension. +### Local Skill Service Module +The Local Skill Service module provides a multipurpose service to the Auto SDK Engine that enables components running alongside the offline Alexa endpoint to communicate with the Auto SDK Engine. The module infrastructure is necessary for other modules in the LVC extension. +### Local Navigation Module +The Local Navigation module enables you to provide customers with offline Alexa local search and navigation to points of interest (i.e., categories, chains, and entities) and addresses. +### Address Book Local Service Module +The Address Book Local Service module works with the Address Book module and the Local Skill Service module to augment the offline communications and navigation capabilities of Alexa with user data such as phone contacts and navigation favorites. +### Car Control Local Service Module +The Car Control Local Service module works with the Car Control module and the Local Skill Service module to enable users to control vehicle features offline with Alexa. + +## Mobile Authorization Extension +The Mobile Authorization extension enables applications running on the vehicle's head unit to simplify the login experience. To log in to Alexa, the user uses the Alexa mobile app on a paired smartphone instead of opening a web browser and entering a code. + +## Voice Chrome for Android Extension +The Voice Chrome extension adds Voice Chrome support to the Auto SDK for Android x86 64-bit and Android ARM 32/64-bit platforms. Voice Chrome provides a consistent set of visual cues representing Alexa attention state across a range of Alexa-enabled devices. The Voice Chrome extension includes a prebuilt Android AAR library for easy integration with your applications, as well as a patch to the Android Sample App that adds the Voice Chrome functionality. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..b204f9fcd --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +### Security Policy for Device SDKs +Amazon has updated the AVS API to add a new consent screen during device registration for new users if the device has not been not certified by Amazon. Once the device has completed the testing process including obtaining a security assessment from Authorized Security Lab and receiving an Alexa Built-in badge, this consent screen will be removed and developers will be able to offer the full Alexa experience on their Alexa Built-in devices. To learn more about device testing and certification, please visit [here](https://developer.amazon.com/en-US/alexa/devices/alexa-built-in/development-resources#additional-resources). + +### Reporting a Vulnerability +If you discover a potential security issue in this project we ask that you notify Alexa Voice Services Security team by sending an email to . Please do **not** create a public GitHub issue. \ No newline at end of file diff --git a/aacs/android/README.md b/aacs/android/README.md new file mode 100644 index 000000000..8bd351a7d --- /dev/null +++ b/aacs/android/README.md @@ -0,0 +1,832 @@ +# Alexa Auto Client Service (AACS) +Alexa Auto Client Service (AACS) is an Alexa Auto SDK feature packaged in an Android archive library (AAR). By providing a common service framework, AACS simplifies the integration of the Auto SDK with your Android device and supports all the Auto SDK extensions. + +Your application communicates with AACS through an intent, which is a messaging object on an Android device. AACS provides the platform implementation for certain interfaces, which speeds up Alexa integration for in-vehicle infotainment (IVI). Without AACS, typical integration of the Auto SDK in the IVI involves the implementation of abstract interfaces provided by each Auto SDK module to handle platform-specific functionality. To implement all required platform interfaces, the Auto SDK is integrated to an event-based system that converts from direct method APIs to an event-based architecture. + +This document assumes that you understand how the Auto SDK works, as described in the [Auto SDK README](../../README.md). When this document uses the term "application," it refers to the application you develop on the Android platform. Information for your application in this document also applies to your Android service. + + +## Table of Contents +- [AACS Architecture](#aacs-architecture) +- [Obtaining the AACS AAR](#obtaining-the-aacs-aar) +- [Using AACS with Your Application](#using-aacs-with-your-application) + - [AACS as Foreground Service or System Service](#aacs-as-foreground-service-or-system-service) + - [AACS Initialization and Configuration](#aacs-initialization-and-configuration) +- [Default Platform Implementation](#default-platform-implementation) + - [Property Content Provider Implementation (Optional)](#property-content-provider-implementation-optional) + - [Enabling AACS to synchronize Alexa's Time Zone and Locale with Device Settings (Optional)](#enabling-aacs-to-synchronize-alexas-time-zone-and-locale-with-device-settings-optional) + - [Using Custom Domain Module with CustomDomainMessageDispatcher Enabled (Optional)](#using-custom-domain-module-with-customdomainmessagedispatcher-enabled-optional) +- [Specifying the Intent Targets for Handling Messages](#specifying-the-intent-targets-for-handling-messages) + - [Using Android Manifest](#using-android-manifest) + - [Using AACS Configuration File](#using-aacs-configuration-file) +- [Platform Implementation in Your Application](#platform-implementation-in-your-application) + - [Initial Authentication Sequence Diagram](#initial-authentication-sequence-diagram) + - [Wake Word Enabled Sequence Diagram](#wake-word-enabled-sequence-diagram) +- [Client Utility Library](#client-utility-library) +- [Device Settings Required for AACS](#device-settings-required-for-aacs) +- [Checking AACS Connection State](#checking-aacs-connection-state) +- [Request list of extras from AACS](#request-list-of-extras-from-aacs) +- [Using Instrumentation](#using-instrumentation) +- [Including App Components with AACS AAR in your application](#including-app-components-with-aacs-aar-in-your-application) +- [AACS Sample App](#aacs-sample-app) + +## AACS Architecture +The following diagram shows the high-level architecture of AACS on the Android platform. The shaded boxes in the diagram represent components developed by Amazon that are packaged in AACS. + +

+ +

+The following list describes the components in the AACS service layer, as illustrated in the diagram, and how they interact with one another and with the Auto SDK: + +1) **AlexaAutoClientService** is a persistent service that can start automatically after device boot-up or be manually started by an application through a `startService()` call. The service performs the following functions: + + * Instantiating the Auto SDK Engine. + * Creating and registering the AASB message handler with the AASB MessageBroker. + * Setting the required Engine configuration. + * Managing the notifications displayed in the system notification area. + +2) **PhoneControlMessagingImpl** and **NavigationMessagingImpl** are messaging implementations that serialize direct API calls into a standardized message format. The `PhoneControlMessagingImpl` or `NavigationMessagingImpl` converts platform interface +method parameters into the message payload of the respective messaging implementation. The message is then sent to the service layer by using the AASB `MessageBroker` with a specific message topic and action. The messaging implementation also subscribes to message topics that are sent from the human-machine interface (HMI) application to the Auto SDK. +3) **AudioInputImpl**, **AudioOutputImpl**, **ExternalMediaPlayerImpl**, and **AdditionalPlatformImpl** are the direct implementations of Auto SDK platform interfaces. You can enable or disable the implementations in the AACS AAR through the configuration file. If an implementation is disabled, the platform message handler must be provided by a client application. +4) **AASB MessageBroker** is an abstraction built on top of the Auto SDK core. `MessageBroker` routes messages between the application and the Auto SDK core. When the +application responds to `MessageBroker` with an event, the event is routed back through the platform interface implementation. +5) **AASB MessageHandler** implements the platform-specific logic to send and receive AASB messages. +6) **Mediaplayer** handles the default AudioOutput actions, such as prepare, play, and pause for a TTS channel. +7) **IPCLibrary** defines the protocol for the communication between the HMI application and AACS. +It provides the APIs for sending and receiving AASB Messages over the Android Intent/Binder interface and +supports streaming audio data to and from an external application. It builds into an Android archive (AAR) file, which you can include in other apps that need to communicate with AACS. For more information about the IPC, see this [README](common/ipc/README.md). +1) **LVCInteractionProvider** implements APIs defined by the `ILVCClient` Android Interface Definition Language (AIDL) file to connect with `ILVCService`, which is implemented by the Local Voice Control (LVC) application. This connection also enables the LVC APK to provide the configuration for LVC. +2) The core of the **HMI application** that holds the business logic need not change with +`AlexaAutoClientService`. However, you must modify the application so that it can interface with the APIs defined by AACS. + +## Obtaining the AACS AAR +AACS is packaged as an Android library (AAR). You can obtain the AACS AAR in one of two ways: + +* To obtain the pre-built AACS AAR and the other dependency AARs which are required for using AACS, contact your Amazon Solutions Architect (SA) or Partner Manager for more information. + +* To build the AACS AAR from source code, following the steps below. + 1) Enter the following command to change the directory: + ~~~ + cd ${AAC_SDK_HOME}/aacs/android/service + ~~~ + + 2) Enter the following command to start the local build. + ~~~ + ./gradlew assembleLocalRelease + ~~~ + This command builds AACS core service, as well as all the other needed dependencies (such as Auto SDK) required for AACS to function. It also generates AAR files that are used for communicating with AACS from your application. + + To install all the generated AARs to your application, add the `installDeps` task after the build command. Specify the path you want the artifacts to be installed to by using the `-PinstallPath` option. If `-PinstallPath` is not specified, the artifacts will be copied to `alexa-auto-sdk/aacs/android/service/deploy` by default. + ~~~ + ./gradlew assembleLocalRelease installDeps -PinstallPath= + ~~~ + + +## Using AACS with Your Application +This section provides information about how AACS works with your application. + +To build your application with AACS, you can either include AACS and the other dependencies as local sub-projects, or you can build them as AARs and copy to the libs folder of your application. + +1. Using AACS as a local module + + Include AACS and the other dependency libraries as sub-projects in the `settings.gradle` file of your project. + In the `build.gradle` file of your application, add the following `implementation` statements: + ~~~ + implementation project(':aacs') + implementation project(':aacs-extra') + implementation project(':aacs-maccandroid') + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':aacscommonutils') + implementation project(':alexa-auto-tts') + + // replace the placeholder with your path + implementation fileTree(include: ['*.aar'], dir: ) + ~~~ + See the [settings.gradle](../android/sample-app/settings.gradle) and the [build.gradle](../android/sample-app/alexa-auto-app/build.gradle) of AACS Sample App for more information. + +2) Using AACS as a local binary + + Include the AARs in the libs folder of your application. See [Obtaining the AACS AAR](#obtaining-the-aacs-aar) for instructions of how to obtain the AACS AARs. + + Add the following `implementation` statement to the `build.gradle` file of your application: + ~~~ + implementation fileTree(dir: 'libs', include: ['*.aar']) + ~~~ + +### AACS as Foreground Service or System Service +AACS runs as a started service on Android. The [Initialization](#initialization) section describes how it is started; this section describes what you do to run AACS as a foreground service or a system service. + +#### As Foreground Service +Typically, AACS is started as a foreground service, which has higher priority and continues running unless it is under memory constraints. In addition, the service displays notifications to alert the user that it is running. + +To run AACS as a foreground service, in the AACS configuration, set `persistentSystemService` under `aacs.general` to +`false`. Then your application can use the `startForegroundService()` function to initialize AACS. If AACS is started properly, a notification is displayed. + +Since Android 8.0 (API level 26), foreground services have had +some changes in how they are initialized. The following code checks the Android version and calls the correct API: +~~~ +Intent intentStartService = new Intent(); +intentStartService.setComponent(new ComponentName(AACSConstants.getAACSPackageName(new WeakReference(context)), +"com.amazon.alexaautoclientservice.AlexaAutoClientService")); +intentStartService.setAction(Action.LAUNCH_SERVICE); + +if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + startForegroundService(intent); +} else { + startService(intent); +} +~~~ + +#### As Persistent System Service +If you have root access on the device and your application containing AACS AAR is a system application, you can configure AACS to run as a system service. In the AACS configuration, set `persistentSystemService` under `aacs.general` to `true`. +~~~ +"aacs.general" : { + "persistentSystemService": true, + ... +} +~~~ +This setting is equivalent to setting the 'persistent' flag to true within the `application` element of the Android Manifest file. This flag indicates that the service runs at all times, and should only be set to true by system applications. Your application no longer needs to start AACS in the foreground, and no notifications appear to show that the service is running. The following example shows an application starting AACS as a system service: +~~~ +Intent intentStartService = new Intent(); +intentStartService.setComponent(new ComponentName(AACSConstants.getAACSPackageName(new WeakReference(context)), +"com.amazon.alexaautoclientservice.AlexaAutoClientService")); +intentStartService.setAction(Action.LAUNCH_SERVICE); + +startService(intent); +~~~ + +### AACS Initialization and Configuration +Initializing AACS means getting AACS ready to communicate with other applications. However, Alexa functionality is not available until AACS receives the configuration. + +#### Initialization +There are two ways to initialize AACS: + +* Start AACS from an application: +AACS includes a permission that determines whether an application can start or stop the service. For an application to start or stop AACS, specify the permission name in the application's `AndroidManifest.xml` file as follows: + + `` + + For an example of starting AACS from an application, see [example for starting AACS as a system service](#as-persistent-system-service). + +* Start AACS upon device boot: If you want AACS to start every time the user turns on the device, set `startOnDeviceBootEnabled` in `aacs.general` of your configuration to `true`. Due to this setting, AACS initiates a `startService()` call on itself when it receives the `BOOT_COMPLETED` intent, which the device broadcasts when it is finished booting. + + >**Important!** The device considers AACS inactive until AACS is run at least once. AACS does not start automatically on device boot unless AACS is considered active. Simply run AACS at least once after installation, and AACS will start each time the device is restarted. + +Whether `startOnDeviceBootEnabled` is set to `true` or `false`, the application can always send a `startService()` or `stopService()` call to start or stop AACS. + +#### Configuration Schema +This section describes the configuration schema, which includes Auto SDK engine configuration, general service behavioral settings, and definitions for how AACS interfaces with applications. For more information about AACS configuration, see [Configuration Reference documentation](service/README.md). + + >**Important!** Some configuration fields may require you to provide filepaths. These filepaths must be absolute paths that are accessible to AACS. AACS will not accept filepaths to public locations (such as SD card) for security reasons. + +The sample configuration JSON file in this section illustrates the AACS configuration structure. Be sure to fill out the following required sections under `deviceInfo` of `aacs.alexa`: + * `clientId` + * `productId` + * `deviceSerialNumber` + +The following documents provide more information about configuration: + +* [Auto SDK class list](https://alexa.github.io/alexa-auto-sdk/docs/cpp/annotated.html) +* [Complete configuration file](./assets/config.json) +~~~ +{ + "aacs.alexa": { + "deviceInfo": { + "clientId": "", + "productId": "", + "deviceSerialNumber": "", + "manufacturerName": "name", + "description": "description" + }, + "localMediaSource": { + "types": [] + }, + "audio": { + "audioOutputType.music": { + "ducking":{ + "enabled": true + } + } + }, + "requestMediaPlayback": { + "mediaResumeThreshold": 50000 + } + }, + "aacs.vehicle": { + "info": { + "make": "Amazon", + "model": "AACE", + "year": "2020", + "trim": "aac", + "geography": "US", + "version": "1.2.3", + "os": "Sample OS 1.0", + "arch": "Sample Arch 1.0", + "language": "en-US", + "microphone": "SingleArray", + "countries": "US,GB,IE,CA,DE,AT,IN,JP,AU,NZ,FR", + "vehicleIdentifier": "Sample Identifier ABC" + }, + "operatingCountry": "US" + }, + "aacs.cbl": { + "enableUserProfile": false + }, + "aacs.carControl": { + "endpoints":[], + "zones":[] + }, + "aacs.general" : { + "version": "1.0", + "persistentSystemService": false, + "startServiceOnBootEnabled": true, + "intentTargets" : { + "AASB" : { + "type": ["RECEIVER"], + "package": [], + "class": [] + }, + "APL" : { + "type": ["RECEIVER"], + "package": [], + "class": [] + }, + ... (Other topics omitted) + } + }, + "aacs.defaultPlatformHandlers": { + "useDefaultLocationProvider": true, + "useDefaultNetworkInfoProvider": true, + "useDefaultExternalMediaAdapter": true, + "useDefaultPropertyManager": true", + "audioInput": { + "audioType": { + "VOICE": { + "useDefault": true, + "audioSource": "MediaRecorder.AudioSource.MIC", + "handleAudioFocus" : true + }, + "COMMUNICATION": { + "useDefault": true, + "audioSource": "MediaRecorder.AudioSource.MIC" + } + } + }, + "audioOutput": { + "audioType": { + "TTS": { + "useDefault": true + }, + "ALARM": { + "useDefault": true + }, + "MUSIC": { + "useDefault": false + }, + "NOTIFICATION": { + "useDefault": true + }, + "EARCON": { + "useDefault": true + }, + "RINGTONE": { + "useDefault": true + }, + "COMMUNICATION": { + "useDefault": true + } + } + } + } + } +~~~ + +#### Sending a Configuration Message +Sending the configuration relies on the provided [IPC library](common/ipc/README.md). This section describes the configuration's basic syntax. + +The message structure consists of two fields, `configFilepaths` and `configStrings`. `configFilepaths` is a String array containing paths to files which hold full or partial configuration JSON. `configStrings` is a String array containing full or partial configurations in the form of escaped JSON Strings. All partial configurations (from filepath or String) will be reconstructed by AACS to be a single, full configuration. We recommend using the `configStrings` option. See the **Important** note on filepaths in the beginning of the [Configuration](#configuration-schema) section. The following code shows an empty `configMessage`: +~~~ +{ + "configFilepaths: [], + "configStrings": [] +} +~~~ +Using an instance of `AACSSender`, the `sendConfigMessageEmbedded()` or `sendConfigMessageAnySize()` method ensures that the configuration message can be sent to AACS. The following example shows how to construct and send the configuration message: + +~~~ +try { + String config = "..."; // configuration read from file + JSONObject configJson = new JSONObject(config); + JSONArray configStringsArray = new JSONArray(); + configStringsArray.put(configJson.toString()); // add escaped JSON string + JSONObject configMessage = new JSONObject(); + configMessage.put("configFilepaths", new JSONArray()); + configMessage.put("configStrings", configStringsArray); + aacsSender.sendConfigMessageAnySize(configMessage.toString(), target, getApplicationContext()); +} catch (JSONException e) { + ... +} +~~~ + +#### File Sharing and Permissions +Some configurable fields for the Auto SDK require paths to files in your application, which is inaccessible to AACS. To enable the Auto SDK to get the file paths, AACS provides a protocol for applications to grant the Auto SDK URI permissions for these files. AACS then creates a local copy of the file in its internal storage and configures the fields for the Auto SDK, using the file path to the local copy to ensure accessibility. Fields that require file sharing are described in documentation. Currently, only installed extensions have configurable fields that need file sharing. See the AACS README for your extension for more information about file sharing. + +AACS's file sharing protocol uses Android's `FileProvider` class to securely receive the URIs of files in applications. See the [Android documentation](#https://developer.android.com/training/secure-file-sharing/setup-sharing) on how to set up `FileProvider` in your application. Your `FileProvider` is functional after the application includes a `` element in its AndroidManifest and a `filepaths.xml` file for specifying shareable paths. + +After `FileProvider` is set up, AACS expects to receive an intent with action `Intent.ACTION_SEND_MULTIPLE` to include the URIs of files to be shared. Send the intent **after** service initialization but **before** the configuration message is sent. It requires the following structure: +* **Action:** `Intent.ACTION_SEND_MULTIPLE` - The standard Android intent for sharing multiple pieces of content +* **Type:** The MIME type of a URI +* **Extra:** `AACSConstants.CONFIG_MODULE` or `configModule`- A `String` representing the module to be configured by the shared files +* **ParcelableArrayListExtra:** `Intent.EXTRA_STREAM` - An `ArrayList` containing URIs of files to be shared + +Before sending the intent, be sure to grant the `Intent.FLAG_GRANT_READ_URI_PERMISSION` to AACS for each URI being sent. Also, because the intent holds multiple file URIs for a single configuration module at a time, if there are multiple files for separate modules, send multiple intents, as shown in the following example implementation: + +~~~ +private void shareFilePermissionsOfSameModule(File parent, String[] filenames, String module) { + ArrayList fileUris = new ArrayList<>(); + for (String name : filenames) { + File file = new File(parent, name); + Uri fileUri = FileProvider.getUriForFile( + MainActivity.this, + , + file); + grantUriPermission(AACSConstants.getAACSPackageName(new WeakReference(context)), fileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + fileUris.add(fileUri); + } + + Intent shareFileIntent = new Intent(); + shareFileIntent.setComponent( + new ComponentName(AACSConstants.getAACSPackageName(new WeakReference(context)), AACSConstants.AACS_CLASS_NAME)); + shareFileIntent.setAction(Intent.ACTION_SEND_MULTIPLE); + shareFileIntent.setType(getContentResolver().getType(fileUris.get(0))); + shareFileIntent.putExtra(AACSConstants.CONFIG_MODULE, module); + shareFileIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, fileUris); + startForegroundService(shareFileIntent); +} +~~~ + +>**Note:** `AACSConstants.AACS_PACKAGE_NAME` is deprecated and it shall be removed from the future Alexa Auto SDK versions. Use `AACSConstants.getAACSPackageName(Context)` instead. + +#### Initialization Protocol +After starting the service, send file sharing intents for any files outside of AACS's access that will be needed for configuration. Then, send the configuration message. If there are no files to be shared, the configuration can be sent immediately after AACS is initialized. The configuration is not part of the initial intent to start the service because intents in Android have size limits, which the configuration might exceed. Using the provided IPC library allows for sending configuration of any size. + +Because AACS stores the last configuration received, the only requirement is that the configuration is sent the first time AACS is run +after installation. At any subsequent start, AACS uses the stored configuration. Similarly for shared files, AACS retains local copies of the files, +so file sharing intents do not have to be re-sent in subsequent launches. + +However, updating the stored configuration (without uninstalling the application containing AACS AAR) requires that the +`startService` intent include an `Extras` field called `newConfig`. `newConfig` holds a +boolean value that alerts AACS not to start running with the stored configuration, but wait for a new configuration message. +In addition, whenever the `newConfig` field is set to `true`, AACS clears all local copies of shared files +and expect new file sharing intents, if necessary for the new configuration. + +**Note**: The old configuration is overwritten by the new configuration. + +For your application to start AACS with a new configuration, make sure your intent includes `newConfig`, as shown in the following example: + +~~~ +Intent intentStartService = new Intent(); +intentStartService.setComponent(new ComponentName(AACSConstants.getAACSPackageName(new WeakReference(context)), +"com.amazon.alexaautoclientservice.AlexaAutoClientService")); +intentStartService.setAction(Action.LAUNCH_SERVICE); +intentStartService.putExtra("newConfig", true); +~~~ + +Omitting `newConfig` is the same as setting it to `false`, which causes AACS to use the stored configuration. + +**Important**: Sending a new configuration is allowed only once per service run. After AACS is configured and +running, AACS ignores subsequent attempts to update the configuration, even if the `newConfig` field is `true`. To update an existing configuration, you must +stop the service and restart it with `newConfig` set to `true`. This same rule applies to file sharing intents. + +#### Initialization Sequence Diagram +The following diagram shows an example of initializing AACS from an app used by a driver. +

+ +

+ +## Default Platform Implementation +Default platform implementations refer to implementations of Auto SDK platform interfaces that AACS provides to replace the normal protocol of using AASB messages. By enabling a default platform implementation in AACS, you no longer have to handle messages for a particular platform interface and can rely on AACS to provide the necessary functionality. + +AACS provides a default implementation for these platform interfaces: +* AudioInput (audioType: VOICE, COMMS) +* AudioOutput (audioType: TTS, ALARM, NOTIFICATIONS, EARCON, RINGTONE) +* LocationProvider +* NetworkInfoProvider +* ExternalMediaAdapter for Media App Command and Control (MACC) +* LocalMediaSource +* PropertyManager + +The platform implementations for these interfaces are disabled by default; the AASB messages for these interfaces are routed to the [client app to be handled](#specifying-the-app-targets-for-handling-messages). + +To enable the default platform implementation in AACS, you must set the `aacs.defaultPlatformHandlers` +configuration flags. In the following example, you use `aacs.defaultPlatformHandlers` in the +configuration file to instruct AACS to handle `LocationProvider` and `NetworkInfoProvider`, `AudioInput` for `VOICE`, and +`AudioOutput` for `TTS`. Specific apps handle the other messages. + +~~~ +"aacs.defaultPlatformHandlers": { + "useDefaultLocationProvider": true, + "useDefaultNetworkInfoProvider": true, + "useDefaultExternalMediaAdapter": true, + "useDefaultPropertyManager": true", + "audioInput": { + "audioType": { + "VOICE": { + "useDefault": true, + "audioSource": "MediaRecorder.AudioSource.MIC", + "handleAudioFocus" : true + }, + } + }, + "audioOutput": { + "audioType": { + "TTS": { + "useDefault": true + }, + "MUSIC": { + "useDefault": false + }, + ... other audio types + } + } + } +~~~ + +### Property Content Provider Implementation (Optional) + +AACS supports the Android `ContentProvider` class, which is a standard Android mechanism for performing CRUD (Create, Read, Update, Delete) operations on stored data. By extending this class, you can use a content provider, instead of AACS messages, to manage Auto SDK properties and retrieve state information. Using a content provider offers the following advantages: + +* AACS can consistently provide the properties across multiple launches. Because properties are persistent, your application does not need to reset the properties after each AACS restart. + +* AACS messages are asynchronous, which might cause timeouts and subsequently incorrect or error states. Using a content provider to retrieve state data makes the retrieval process synchronous, thus guaranteeing that the request for state information reaches its destination and a response is received. + +* ContentProvider is the standard Android mechanism for performing CRUD (Create, Read, Update, Delete) operations on stored data. + +#### Sequence Diagram and Overview + +The following sequence diagram illustrates the workflow for the default property manager implementation in AACS. This implementation provides the interface, based on the Android `ContentProvider`, for OEM apps to get and set Auto SDK properties. + +~~~ +aace.alexa.wakewordSupported +aace.alexa.system.firmwareVersion +aace.alexa.setting.locale +aace.alexa.countrySupported +aace.alexa.timezone +aace.alexa.wakewordEnabled +aace.vehicle.operatingCountry +aace.core.version +aace.network.networkInterface +~~~ + +By using the native Android `ContentProvider` class, you can initiate `query` and `update` operations. query retrieves and returns the current String value of an Auto SDK property. `update` sets an Auto SDK property in the Engine and returns a boolean value based on the success of the operation. Insert and Delete operations are disabled for Auto SDK properties. + +

+ +

+ +#### Implementation Examples +1. Add `useDefaultPropertyManager` in the `config.json` file and set it to `true`, as shown in the following example: + +~~~ +... + "aacs.defaultPlatformHandlers": { + "useDefaultLocationProvider": true, +--> "useDefaultPropertyManager": true, + "audioInput": { + "audioType": { +... +~~~ + +2. Add `READ_USER_DICTIONARY` permission to `AndroidManifest.xml` in your application, as shown in the following example: +~~~ + + { + getContentResolver().update(uri, cv, propertyName, null); + }); + } +} +~~~ + +#### Important Considerations for Using ContentProvider + +* AACS Property Content Provider does not support the `insert` and `delete` APIs in Property ContentProvider; + +* You must use AACS with the AmazonLite Wake Word extension if you want to update `aace.alexa.wakewordEnabled` property; + +* `aace.alexa.countrySupported` is a deprecated property and cannot be get/set; + +* `aace.alexa.wakewordSupported` and `aace.core.version` are read-only properties acquired when building Auto SDK and cannot be set. + +* Valid property value for `aace.alexa.wakewordEnabled` is `true` or `false`. All the other Auto SDK properties will be validated by Auto SDK. Auto SDK will provide value validation for `aace.alexa.wakewordEnabled` in the future. + +### Enabling AACS to synchronize Alexa's Time Zone and Locale with Device Settings (Optional) +AACS supports synchronizing Alexa's time zone and locale properties with the ones in device settings. To enable the functionality, refer to this [README](service/README.md#syncsystempropertychange) for proper configuration. Once enabled, AACS will synchronize the time zone and/or locale properties of Alexa with the device settings in the following conditions: +* When Auto SDK engine is initialized, AACS tries to synchronize both properties with the device settings. The property change would fail and not take effect if the system locale is not supported by Alexa. +* When the authorization state is refreshed, AACS tries to synchronize both properties with the device settings. The property change would fail and not take effect if the system locale is not supported by Alexa. +* When AACS gets `android.intent.action.LOCALE_CHANGED` intent as a result of device locale setting change, Alexa locale property will be updated if the locale is supported by Alexa. +* When AACS gets `android.intent.action.TIMEZONE_CHANGED` intent as a result of device time zone setting change, Alexa time zone property will be updated. + +You can also disable the automatic synchronization for specific properties. This is particularly useful when your application wants to disable/enable the synchronization at runtime. For example, after the user manually selects a locale, you may want to disable the synchronization to allow the user's selection to override the system setting changes. To achieve this use case, your application can send intents with the metadata below to AACS: +* Action: + * Disable: `com.amazon.aacs.syncSystemPropertyChange.disable` + * Enable: `com.amazon.aacs.syncSystemPropertyChange.enable` +* Category: `com.amazon.aacs.syncSystemPropertyChange` +* Extra: `"property": ` + +If this feature is not enabled, your application can still have the full flexibility in changing the two properties by handling AASB Property Manager messages. + +Additionally, you can configure AACS to update the system time zone if the user changes the Alexa's time zone for the device (e.g. the user can change the property on their Alexa mobile app). To enable the functionality, refer to this [README](service/README.md#updatesystempropertyallowed) for proper configuration. Your application with AACS needs to be a system application with android permission `android.permission.SET_TIME_ZONE` obtained. + +**Note:** Always provide the system permission `android.permission.SET_TIME_ZONE` when AACS AAR is in a system application. Refer to [Privileged Permission Allowlisting](https://source.android.com/devices/tech/config/perms-allowlist) in Android documentation. + +### Using Custom Domain Module with CustomDomainMessageDispatcher Enabled (Optional) +To use Custom Domain module with AACS, you need to explicitly enable it first by adding module enablement configuration. Please refer to [AACS Configuration README](service/README.md#aacs-module-enablement) to enable the Custom Domain module. + +By default, all the Custom Domain intents share the same `com.amazon.aacs.aasb.customDomain` intent category. If CustomDomainMessageDispatcher is enabled, the intent category will be the namespace of the custom interface prefixed with `com.amazon.aacs.customDomain`, which allows AACS to dispatch the Custom Domain AASB messages from the engine to the proper components in your system based on the custom namespace. + +Below is the intent schema of the intents sent from the dispatcher. All the intents are sent with our [IPC library](common/ipc/README.md). You can use `AACSReceiver` to receive and process the AASB Custom Domain messages in the intents. + +* Intent for handling/canceling a custom directive: + + * Action: `com.amazon.aacs.customDomain.`. + * Category: `com.amazon.aacs.customDomain.`. + +* Intent for getting the context for a custom namespace: + + * Action: `com.amazon.aacs.customDomain.GetContext` + * Category: `com.amazon.aacs.customDomain.`. + +You can define intent filters in the Android Manifest of your applications to subscribe to the specific Custom Domain intents. See [Specifying the Intent Targets for Handling Messages Using Android Manifest](#using-android-manifest) to learn more about specifying intent targets. +Please refer to this [README](service/README.md#usedefaultcustomdomainmessagedispatcher) on enabling CustomDomainMessageDispatcher. + +>**Note**: CustomDomainMessageDispatcher does not process any custom directives. Your application is responsible for handling any custom directives, sending custom events, and providing custom contexts following the [Custom Domain AASB Documentation](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/custom-domain/aasb-docs/CustomDomain/index.html). If the dispatcher is not enabled, your application will be responsible for receiving all the Custom Domain AASB Messages (as intents) at one place. + +## Specifying the Intent Targets for Handling Messages + +The AASB message intent targets can be `ACTIVITY`, `RECEIVER`, or `SERVICE`. There are two ways to specify the intent targets for AASB message intents from AACS. + +### Using Android Manifest +You can define intent filters in your application's Android Manifest. The intent filter must exactly match the intents' categories and actions. In the intent filter for an intent that wraps an AASB message, specify the category as `com.amazon.aacs.aasb.` and action as `com.amazon.aacs.aasb.`. + +The following example shows an intent filter of all the CBL message intents for a broadcast receiver target: +~~~ + + + + + + + + + + +~~~ +To receive the message specified through the Android Manifest, the application must also have `com.amazon.alexaautoclientservice` permission in its Android Manifest. +~~~ + +~~~ + +Follow these important guidelines if the intent target is an activity: + +* You must add `` to the intent filter as explained [here](https://developer.android.com/guide/components/intents-filters). + +* Be aware that if you start applications with AACS (for example, by specifying Activity as the intent targets from AACS), the target Activity will move to the foreground or become in focus, causing distraction or confusion to the user. AACS does not request `SYSTEM_ALERT_WINDOW` permission to directly create windows on top of all other apps. Amazon recommends using VIS (VoiceInteractionService) to launch activities, and using Android Services or Broadcast Receivers to receive intents from AACS. + +### Using AACS Configuration File +You can use the AACS configuration file to specify the app that can handle AASB messages with a specific "topic". This method of specifying intent targets has the highest priority, meaning it can *override* the ones specified through intent filters in manifests. After you use the AACS configuration to specify the app, intents with all the actions belonging to the topic go to the specified targets. +Fill the optional fields in `intentTargets` in the AACS configuration file as needed. See the [Configuration Reference documentation](service/README.md) for information about `intentTargets`. The following sample configuration shows how to populate `intentTargets` for each topic. The field `type` accepts `RECEIVER`, `ACTIVITY`, and `SERVICE`, depending on the type of the target that handles the intents with the topic. The targets can be broadcast receiver, application activity, and service. + +The format for specifying AASB message intent targets for an AASB message topic is as follows: +~~~ +"" : { + "type": [, , ...], + "package": ["", "", ...], + "class": ["", "", ...] +}, +~~~ + +The following example shows two topics, which are `AASB` and `APL`: +~~~ + "aacs.general" : { + "intentTargets" : { + "AASB" : { + "type": ["ACTIVITY"], + "package": ["com.amazon.aacstestapp"], + "class": ["com.amazon.aacstestapp.MainActivity"] + }, + "APL" : { + "type": ["RECEIVER"], + "package": ["com.amazon.aacstestapp"], + "class": [".IntentReceiver"] // short version of class name is also accepted. + }, // In this case, the class must be in the package specified in "package". + // ... other topics + } + } +~~~ + +**NOTE**: If a given "topic" is specified both in the configuration file and the +Android Manifest, the configuration file takes priority and the targets with intent filters are ignored. Amazon recommends intent filters when possible. Use the configuration approach only if you need to override the existing intent filters. + +AACS first searches for targets for an intent with a topic in the configuration file. If nothing is found, the package manager scans the intent filters on the device to locate a match. AACS also caches the scan results based on both topic and action. The cache is cleared every time AACS is restarted. + +## Platform Implementation in Your Application +Your applications can register for specific AASB messages and provide a platform implementation. For example, an application (“Login app") can register for Authorization messages. For information about the Authorization module, see the [Core Module README](../../modules/core/README.md). + +### Initial Authentication Sequence Diagram +The following sequence diagram illustrates how an application (“Login app") exchanges messages with AACS over Android Intents to log in the user for Alexa. + +

+ +

+ +### Wake Word Enabled Sequence Diagram +The sequence diagram illustrates the sequence for the user to access Alexa if you use the default implementation of AudioInput in AACS. In this diagram, the driver is logged in and wake word is enabled. The driver initiates the action by uttering the Alexa wake word. +

+ +

+ +1. Audio is processed locally by the wake word engine in AACS until the wake word is detected. Upon wake word detection, AACS notifies the application that the dialog state has changed to "listening" and initiates a Recognize event with Alexa. + +2. While in the listening state, audio data is sent to Alexa. When the end of speech is detected, Alexa sends a `StopCapture` directive to AACS, and the dialog state is changed to "thinking." Alexa then responds with additional directives in response to the speech request. + +For information about other messages to provide your implementation in the client APK, please refer to the README for each Auto SDK module. + +## Client Utility Library + +AACS also provides an optional library, [AACS Common Utils](common/commonutils/README.md). It contains useful methods to make messaging with AACS easier. You can use it as-is or as a reference to facilitate the integration of the Auto SDK with AACS. For information about the library, see [AACS Common Utils README](common/commonutils/README.md) and in-code documentation in the library. + +## Device Settings Required for AACS +AACS requires microphone and location permissions when the default implementation is used for AudioInput and Location. If AACS runs in a system application, you can grant these permissions so that the application users do not have to set the permissions. Otherwise, be sure to instruct your users to grant the following permissions on the app info page under Settings on their device: + +* Location: Enable `android.permission.ACCESS_FINE_LOCATION` to give AACS access the current location. + +* Microphone: Enable `android.permission.RECORD_AUDIO` to give permission to AACS to record audio. Microphone must be enabled if you configure AudioInput to use the default implementation of AACS. + +## Checking AACS Connection State +Your application or service can check the status of AACS by using `ping`, which returns a response as long as AACS is running. The `AACSPinger` utility class from the IPC library enables you to use `ping`. + +To ping AACS, specify the ping permission name in your application's Android Manifest file as follows: + +~~~ + +~~~ + +The following example shows how to use `AACSPinger`: + +~~~ +AACSPinger aacsPinger = new AACSPinger(getApplicationContext(), + "com.amazon.alexaautoclientservice.ping"); + +Future fut = aacsPinger.pingAACS(); + +AACSPinger.AACSPingResponse response = fut.get(); + +if (response.hasResponse) { + // Ping was responded to by AACS + String state = response.AACSState; + ... +} else { + // Ping timed out without an AACS response +} +~~~ + +If AACS responds to the ping request, the `AACSPingResponse.AACSState` string returned by `AACSPinger.pingAACS()` has one of the following values: + +* `STARTED` +* `WAIT_FOR_LVC_CONFIG` +* `CONFIGURED` +* `ENGINE_INITIALIZED` +* `CONNECTED` +* `STOPPED` + +If AACS does not respond within the default timeout of 1 second, `AACSPingResponse.hasResponse` is `false`. + + +## Request list of extras from AACS + +Your application can receive the list of AACS extra modules by sending an intent with the action `AACSConstants.IntentAction.GET_SERVICE_METADATA` and the category `AACSConstants.IntentCategory.GET_SERVICE_METADATA`, which returns a response by receiving an intent `AACSConstants.IntentAction.GET_SERVICE_METADATA_REPLY`. + +To get the extras list from AACS- + +- Specify the permission name in your application's Android Manifest file as follows: + +~~~ xml + +~~~ + +- Register a receiver in you application's Android Manifest file as follows: +Following block shows an example of requesting list of extras: + +~~~ xml + +~~~ + +- Send a request intent to AACS. Following code snippet shows an example + +~~~ java +Intent intent = new Intent(); +intent.setAction(AACSConstants.IntentAction.GET_SERVICE_METADATA); +intent.addCategory(AACSConstants.IntentCategory.GET_SERVICE_METADATA); +intent.putExtra(AACSConstants.REPLY_TO_PACKAGE, getPackageName()); +intent.putExtra(AACSConstants.REPLY_TO_CLASS, .class.getName()); +intent.putExtra(AACSConstants.REPLY_TYPE, "RECEIVER"); +sendBroadcast(intent); +~~~ + +- Your receiver class will receive an intent with the following payload + +~~~ json +{ + "metaData": { + "extrasModuleList": [] + } +} +~~~ + +- You can get the payload from the received intent with action `AACSConstants.IntentAction.GET_SERVICE_METADATA_REPLY`. Following code snippet shows the example: + +~~~ java +String payload = intent.getStringExtra(AACSConstants.PAYLOAD); +~~~ + +## Using Instrumentation +You can use AACS instrumentation to log AASB messages for debugging purposes. For more information about how to use instrumentation, see the [AACS Instrumentation README](./service/core-service/src/debug/java/com/amazon/alexaautoclientservice/README.md). + +>**Note:** You can use instrumentation only if you use the debug option when building the Auto SDK with AACS. + +## Including App Components with AACS AAR in your application +The Auto SDK provides packages (also called "app components") in the [`$AAC_SDK_HOME/aacs/android/app-components`](./app-components) directory. App components could be included in your application along with AACS AAR to speed up the Alexa integration. + +>**Note:** Some app components implement the handling of AASB messages for certain topics, allowing your applications to interface with AACS by using standard Android APIs. If you include such app components in your application with AACS AAR, your application does not need to handle the AASB messages for those particular AASB topics. + +## AACS Sample App +The Auto SDK includes an Android-based application that demonstrates how an application uses AACS. For more information about the AACS Sample App, see the [AACS Sample App README](sample-app/README.md). diff --git a/platforms/android/app-components/alexa-auto-apis/.gitignore b/aacs/android/app-components/alexa-auto-apis/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/.gitignore rename to aacs/android/app-components/alexa-auto-apis/.gitignore diff --git a/aacs/android/app-components/alexa-auto-apis/README.md b/aacs/android/app-components/alexa-auto-apis/README.md new file mode 100644 index 000000000..fbe146700 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apis/README.md @@ -0,0 +1,35 @@ +# Alexa Auto API + +This Alexa Auto API package provides: +* Types that are used across multiple Java packages. A Java package is a collection of related types, which is created to avoid type name collisions. +* Interfaces that allow packages to communicate with each other by using standard Java, as long as the consumer and provider of the interface meet these requirements: + * They are in the same Android Package (APK). + * They are loaded and used in the same process. + +## Component Registry (Service Locator) +To enable a package to locate the implementation of an API, the Alexa Auto API Package defines the component registry interfaces and the mechanism to obtain the component registry (also called the service locator). + +### Consuming Implementations from Other Packages + +The following list explains the component registry interfaces: +* `AlexaAppRootComponent` is a component registry interface with an application scope. It provides interfaces that are in scope for the lifetime of the app. This interface provides access to `AlexaAppScopedComponents`, among other interfaces. +* `AlexaAppScopedComponents` provides interfaces that are available for a limited scope. For example, when an app is in logged-off state, `AlexaAppLoggedOutScopedComponent` can be queried by using `AlexaAppScopedComponents`. + +Any library or application class can obtain `AlexaAppRootComponent` as long as it has the Android context. The following code example illustrates how an app obtains `AlexaAppRootComponent`: + +``` +class MyActivity extends AppCompatActivity { + + public void onStart() { + AlexaApp app = AlexaApp.from(this); + AlexaAppRootComponent componentRegistry = app.getRootComponent(); + componentRegistry.getXYZ().doSomethingUseful(); + } +} +``` + +### Publishing Implementations for Other Packages +How a package publishes the implementation of an API for another package to use depends on the scope, as explained in the following list: + +* App lifecycle implementation: If an object's lifecycle is bound to the lifecycle of an app, then the main Alexa app APK creates an instance of the object and makes it available through the implementation of `AlexaAppRootComponent`. +* Limited scoped implementations: A package can publish scoped components into the component registry to be discovered by other packages. To publish a scoped component, the package can obtain `AlexaAppScopedComponentsActivator` from `AlexaAppRootComponent`. diff --git a/aacs/android/app-components/alexa-auto-apis/build.gradle b/aacs/android/app-components/alexa-auto-apis/build.gradle new file mode 100644 index 000000000..a332808d3 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apis/build.gradle @@ -0,0 +1,50 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 25 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-apis" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation deps.kotlin_stdlib + implementation deps.androidx_appcompat + implementation deps.rxjava3 + implementation deps.androidx_navigation_fragment +} diff --git a/extensions/bluetooth/aacs/android/modules/aacs-bluetooth/proguard-rules.pro b/aacs/android/app-components/alexa-auto-apis/proguard-rules.pro similarity index 100% rename from extensions/bluetooth/aacs/android/modules/aacs-bluetooth/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-apis/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-apis/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-apis/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AnimationProvider.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AnimationProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AnimationProvider.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AnimationProvider.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AssistantManager.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AssistantManager.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AssistantManager.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/AssistantManager.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/EarconProvider.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/EarconProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/EarconProvider.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/EarconProvider.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SettingsProvider.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SettingsProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SettingsProvider.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SettingsProvider.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupController.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupController.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupProvider.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupProvider.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/alexaCustomAssistant/SetupProvider.java diff --git a/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/apl/APLTheme.kt b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/apl/APLTheme.kt new file mode 100644 index 000000000..654021ea6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/apl/APLTheme.kt @@ -0,0 +1,5 @@ +package com.amazon.alexa.auto.apis.apl + +data class APLTheme ( + val themePayload : String? +) \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaApp.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaApp.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaApp.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaApp.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaAppRootComponent.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaAppRootComponent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaAppRootComponent.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/AlexaAppRootComponent.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/ScopedComponent.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/ScopedComponent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/ScopedComponent.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/app/ScopedComponent.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthController.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthController.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthStatus.kt b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthStatus.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthStatus.kt rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthStatus.kt diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt similarity index 93% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt index 7f26196d2..738124153 100644 --- a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt +++ b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthWorkflow.kt @@ -23,7 +23,8 @@ enum class AuthState { Auth_Provider_Auth_Started, Auth_Provider_Logout, Alexa_Client_Connected, - Alexa_Client_Disconnected + Alexa_Client_Disconnected, + Alexa_Client_Auth_Unintialized } data class CodePair ( diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthorizationHandlerInterface.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthorizationHandlerInterface.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthorizationHandlerInterface.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/auth/AuthorizationHandlerInterface.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/BluetoothDevice.kt b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/BluetoothDevice.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/BluetoothDevice.kt rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/BluetoothDevice.kt diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/ContactsController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/ContactsController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/ContactsController.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/communication/ContactsController.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/login/LoginUIEventListener.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/login/LoginUIEventListener.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/login/LoginUIEventListener.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/login/LoginUIEventListener.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/module/ModuleInterface.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/module/ModuleInterface.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/module/ModuleInterface.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/module/ModuleInterface.java diff --git a/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionActivityController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionActivityController.java new file mode 100644 index 000000000..7243735a7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionActivityController.java @@ -0,0 +1,42 @@ +package com.amazon.alexa.auto.apis.session; + +import com.amazon.alexa.auto.apis.app.ScopedComponent; + +import androidx.fragment.app.Fragment; +import io.reactivex.rxjava3.core.Observable; + +/** + * Component that handles getting the session activity and vending + * it out to components that want to inflate its voice fragment onto that activity. + */ +public interface SessionActivityController extends ScopedComponent { + + /** + * Add voice fragment into voice session activity. + * @param fragment voice fragment + */ + void addFragment(Fragment fragment); + + /** + * Remove any existing voice fragment from voice session activity. + */ + void removeFragment(); + + /** + * Get voice fragment which is added into voice session activity. + * @return voice fragment + */ + Fragment getFragment(); + + /** + * Check if voice fragment has been added. + * @return true if added + */ + boolean isFragmentAdded(); + + /** + * Gets an observable that tells us if a voice fragment is inflated. + * @return an observable that informs us whether a voice fragment is inflated. + */ + Observable getFragmentAddedObservable(); +} diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionViewController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionViewController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionViewController.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/session/SessionViewController.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupController.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupController.java diff --git a/platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupWorkflowController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupWorkflowController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupWorkflowController.java rename to aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/setup/AlexaSetupWorkflowController.java diff --git a/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionStatus.kt b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionStatus.kt new file mode 100644 index 000000000..491b619f7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionStatus.kt @@ -0,0 +1,10 @@ +package com.amazon.alexa.auto.apis.uxRestrictions + +data class CarUxRestrictionStatus ( + val isRequiredUXRestriction : Boolean, + val actionRestriction: CarUxRestriction? +) + +data class CarUxRestriction ( + val uxRestrictionName : String +) \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionsController.java b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionsController.java new file mode 100644 index 000000000..cc5b76702 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apis/src/main/java/com/amazon/alexa/auto/apis/uxRestrictions/CarUxRestrictionsController.java @@ -0,0 +1,35 @@ +package com.amazon.alexa.auto.apis.uxRestrictions; + +import com.amazon.alexa.auto.apis.app.ScopedComponent; + +import io.reactivex.rxjava3.core.Observable; + +/** + * API interface to let Alexa App know about the current car UX restrictions state and + * to observe car UX restriction updates. + */ +public interface CarUxRestrictionsController extends ScopedComponent { + /** + * Get active car UX restriction. + * + * @return CarUxRestriction Car UX restriction. + */ + CarUxRestriction getActiveCarUxRestriction(); + + /** + * Fetch observable that can be used to monitor the car UX restrictions changes. + * + * @return Observable of car UX restriction status. + */ + Observable observeCarUxRestrictionChanged(); + + /** + * Register listener for car UX restrictions changes. + */ + void registerListener(); + + /** + * Unregister listener for car UX restrictions changes. + */ + void unregisterListener(); +} diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/.gitignore b/aacs/android/app-components/alexa-auto-apl-renderer/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/.gitignore rename to aacs/android/app-components/alexa-auto-apl-renderer/.gitignore diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/README.md b/aacs/android/app-components/alexa-auto-apl-renderer/README.md new file mode 100644 index 000000000..e6db384f1 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/README.md @@ -0,0 +1,157 @@ +# Alexa Auto APL Renderer + +The Alexa Auto APL Renderer library enables the AACS Sample App to render Amazon Presentation Language (APL) documents on the user's device. The library consists of the following components: + +* `APLReceiver`: This class receives the APL intents. After receiving an APL `RenderDocument` intent, it starts adding `APLFragment` to [VoiceActivity](../alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/VoiceActivity.java) or sends the `APLDirective` event to `APLFragment`. + +* `APLHandler`: This class handles APL intents, such as those for rendering or clearing APL documents. It also executes APL commands and implements an event interface named `IAPLEventSender`, which reports events to Alexa or the capability agent. + +* `APLFragment`: This class initializes the APL runtime, instantiates `APLPresenter`, and calls the `APLhandler` methods to handle APL intents. This class also inflates the APL layout to render the APL document. The `APLLayout` object in [fragment_apl.xml](./src/main/res/layout/fragment_apl.xml) defines the layout. + +**Important!** The Alexa Auto APL Renderer library is for you to experiment with APL document rendering on an automotive device, it is not a preferred UX in automotive experience. Do not use the library to render APL documents in a production vehicle. Support for APL rendering in a production environment will be provided in a future Alexa Auto SDK version. + +**Important!** Certain APL templates recommend scrolling text and these will be removed for production versions of APL in a future Alexa Auto SDK version. + +## Prerequisites for Using the Alexa Auto APL Renderer Library +The APL Renderer library for the AACS Sample App depends on the capabilities provided by an Auto SDK module called APL Render module. For example, the APL Render module provides the `APLPresenter` class implementation. The Alexa Auto APL Renderer library initializes this class to provide the orchestration logic in the APL rendering process. + +For information about how to build the APL Render module, see the [APL Render README](modules/apl-render/README.md). + +## Using Alexa Auto APL Renderer Library with AACS Sample App +To use the Alexa Auto APL Renderer Library with the AACS Sample App, include the appropriate build dependency and configure APL in the AACS Sample App. + +### Including Build Dependency (AAR) + +The Alexa Auto APL Renderer library requires a prebuilt Android view host, which is available as an AAR on the developer portal. To download the AAR, contact your Solutions Architect (SA) or Partner Manager. + +>**Note:** To include the build dependency, you must place the Android view host AAR in the APL Render module [libs/](./modules/apl-render/src/main/libs/) folder. + +### Configuring APL in AACS Sample App + +The AACS Sample App passes `aacs_config.json` to AACS for configuring the Auto SDK. Follow these steps to enable APL and specify the display format: + +1. Enable APL in `aacs_config.json`: + + ```json + "aacs.modules": { + "aacs.apl": { + "APL": { + "enabled": true + } + } + } + ``` + +2. Add the `gui` configuration node in `aacs.alexa`, as shown in the following example: + + ```json + { + "aacs.alexa": { + "gui": { + "visualCharacteristics": [ + { + "type": "AlexaInterface", + "interface": "Alexa.InteractionMode", + "version": "1.1", + "configurations": { + "interactionModes": [ + { + "id": "apl-interaction-id", + "uiMode": "AUTO", + "interactionDistance": { + "unit": "INCHES", + "value": 24 + }, + "touch": "SUPPORTED", + "keyboard": "SUPPORTED", + "video": "SUPPORTED", + "dialog": "SUPPORTED" + } + ] + } + }, + { + "type": "AlexaInterface", + "interface": "Alexa.Presentation.APL.Video", + "version": "1.0", + "configurations": { + "video": { + "codecs": [ + "H_264_42", + "H_264_41" + ] + } + } + }, + { + "type": "AlexaInterface", + "interface": "Alexa.Display.Window", + "version": "1.0", + "configurations": { + "templates": [ + { + "id": "apl-window-id", + "type": "STANDARD", + "configuration": { + "sizes": [ + { + "type": "DISCRETE", + "id": "window-size-id", + "value": { + "unit": "PIXEL", + "value": { + "width": 900, + "height": 1200 + } + } + } + ], + "interactionModes": [ + "apl-interaction-id" + ] + } + } + ] + } + } + ] + } + } + } + ``` + + For descriptions of the visual characteristic parameters, see the [Alexa Smart Screen SDK documentation](https://github.com/alexa/alexa-smart-screen-sdk/blob/master/modules/GUI/config/SmartScreenSDKConfig.md#visual-characteristics-parameters). + APL viewport can be adjusted by changing the width and height pixel values in `Alexa.Display.Window` configuration. + +### Building AACS Sample App with Alexa Auto APL Renderer Library + +To build the AACS Sample App with Alexa Auto APL Renderer library, go to `${AAC_SDK_HOME}/aacs/android/sample-app/` and enter the following command: + +```shell +./gradlew assembleLocalRelease -PenabledAPL +``` + +### Using AACS Sample App + +After the gradle build command finishes building the AACS Sample App, you can test the sample app by asking, "Alexa, tell me a joke." An APL document is rendered on the device. + +The Auto SDK 4.0 enables the ability to report the vehicle driving state to provide safer visual experiences while the vehicles is moving. To enable the driving state support, add `-PenabledUXRestrictions` to the build command. When you say "Alexa, show coffee shops near me" and view the details for a point of interest, the data displayed in the APL detail card will contain more information while the driving state is `parked`. Additionally, the Auto SDK 4.0 supports the ability to report the light conditions around the vehicle to support day/night mode and provide a custom theme id to alter the look and feel of the APL experience. +```shell +./gradlew assembleLocalRelease -PenabledAPL -PenabledUXRestrictions +``` + +>**Note:** The alexa-auto-ux-restrictions requires Android API level 29. Provide your own implementation for the `CarUxRestrictionsController` interface if your device uses API level less than 29. By default, the driving state will always be set to `moving` if the `CarUxRestrictionsController` is not implemented. + +## Known Issues +* When interrupting music playback with APL utterance, APL card will be dismissed when music playback resumes, this issue could not be seen if music ducking support is enabled in AACS sample app. To do this, add audio ducking node in `aacs.alexa`, as shown in the following example: + ``` + "aacs.alexa": { + "audio": { + "audioOutputType.music": { + "ducking":{ + "enabled": true + } + } + } + } + ``` \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/build.gradle b/aacs/android/app-components/alexa-auto-apl-renderer/build.gradle new file mode 100644 index 000000000..ebd5f6efe --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/build.gradle @@ -0,0 +1,88 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "4.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-apl-renderer" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } +} + +dependencies { + implementation(name:'aplRelease', ext:'aar') + implementation(name:'ttsplayerRelease', ext:'aar') + + implementation project(':alexa-auto-apl-renderer:apl-render') + implementation project(':aacscommonutils') + implementation project(':aacsipc') + implementation project(':aacsconstants') + + implementation project(':alexa-auto-apis') + implementation project(":alexa-auto-apps-common-util") + implementation project(":alexa-auto-navigation") + + implementation deps.androidx_appcompat + implementation deps.eventbus + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.androidx_test_core + testImplementation deps.androidx_arch_core_testing + testImplementation deps.roboelectric + + implementation deps.android_appcompat + implementation deps.android_design + implementation deps.android_constraint + implementation deps.android_cardview + implementation deps.android_recyclerview + implementation deps.okhttp + + api deps.google_guava + + // Glide + implementation deps.glide + annotationProcessor deps.glide_compiler + + // RX + implementation deps.rxjava3 + + // Dagger + implementation 'com.google.dagger:dagger-android:2.33' + implementation 'com.google.dagger:dagger-android-support:2.33' + annotationProcessor 'com.google.dagger:dagger-android-processor:2.33' + annotationProcessor 'com.google.dagger:dagger-compiler:2.33' +} diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/gradle.properties b/aacs/android/app-components/alexa-auto-apl-renderer/gradle.properties similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/gradle.properties rename to aacs/android/app-components/alexa-auto-apl-renderer/gradle.properties diff --git a/extensions/extras/.gitignore b/aacs/android/app-components/alexa-auto-apl-renderer/libs/.gitignore similarity index 100% rename from extensions/extras/.gitignore rename to aacs/android/app-components/alexa-auto-apl-renderer/libs/.gitignore diff --git a/platforms/android/modules/apl-render/.gitignore b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/.gitignore similarity index 100% rename from platforms/android/modules/apl-render/.gitignore rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/.gitignore diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/README.md b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/README.md new file mode 100644 index 000000000..6ea74852a --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/README.md @@ -0,0 +1,283 @@ +# APL Render Module + +The APL Render module is an Android library that enables Alexa Presentation Language (APL) rendering capabilities in an Android application. For detailed information about APL, see the [APL documentation](https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/understand-apl.html). + + +## Table of Contents +- [Overview](#overview) +- [Understanding Android View Host](#understanding-android-view-host) +- [APL Render Module Functionality](#apl-render-module-functionality) +- [How to use the APL Render Module](#how-to-use-the-apl-render-module) + - [Defining the APL Layout](#defining-the-apl-layout) + - [Initializing the APL Runtime](#initializing-the-apl-runtime) + - [Implementing the Event Interface](#implementing-the-event-interface) + - [Instantiating APLPresenter](#instantiating-aplpresenter) +- [Rendering an APL Document](#rendering-an-apl-document) +- [Building the APL Render Library](#building-the-apl-render-library) +- [Overriding Android View Host Options](#overriding-android-view-host-options) + - [Using APLOptions.Builder](#using-aploptionsbuilder) +- [APL Extensions](#apl-extensions) + +## Overview +Rendering an APL document on a device requires the implementation of various components and the logic that makes the components work together. To handle APL-related directives and events, the device must support APL interfaces. It needs integration of the [APL Core Library](https://github.com/alexa/apl-core-library) to manage the document parsing and rendering workflow. + +In addition, you must build a view host for the device to render the APL document on the screen, as well as provide components to download layouts, images, and other resources. If the APL document generates multimedia content, such as a video or audio file, you need a media player to play back the content. Lastly, APL rendering needs the orchestration logic to manage the lifecycle of a rendered document, which includes user events, audio focus management, time out management, visual context, command execution, and much more. The Alexa Auto SDK, with the APL Render module and a prebuilt Android view host, simplifies the process of APL rendering because it provides the aforementioned components and logic for you. + +## Understanding Android View Host + +The Android view host is the component responsible for rendering APL on the screen. Amazon provides a prebuilt Android view host as an Android Archive Library (AAR) on the developer portal. To download the AAR, contact your Solutions Architect (SA) or Partner Manager. + +>**Note:** To use the Android Render module, you must place the Android view host AAR in the [src/main/libs/](./src/main/libs) folder of the APL Render module. + +## APL Render Module Functionality + +The APL Render module provides all the functionality needed for enabling APL rendering capabilities in an Android application. The APL Render module provides the following capabilities: + +* APL runtime initialization +* HTTP Resource downloader +* Android view host integration +* Android audio focus management +* Activity tracking for timeout management +* Audio and media players +* Interfaces to easily override functionality + +## How to use the APL Render Module + +To use the APL Render module without customization, follow these steps: + +1) Define the APL layout. +2) Initialize the APL runtime. +3) Implement the event interface. +4) Instantiate `APLPresenter`. + +### Defining the APL Layout + +The application must define the layout of the screen on which the APL document is rendered. the width and height of the `APLLayout` must fall in range with one of the three supported [automotive viewport profiles](https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-alexa-viewport-profiles-package.html): auto extra small, auto small, and auto medium. Define an `com.amazon.apl.android.APLLayout` object, as shown in the following example, where the object is defined under `res/layout`: + +```java + + + + + + +``` + +The `app:aplTheme` field corresponds to the default [APL theme](https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-viewport-property.html#theme) to be used if one is not specified in the APL document. Typical values are `light` or `dark`. + +The `app:mode` field specifies the operating mode, which is a [viewport property](https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-viewport-property.html#viewport_mode_property). For information about the viewport object, see the [viewport documentation](https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-viewport-property.html). The value for this field should be `auto` for an Automotive device. + +### Initializing the APL Runtime + +The application must invoke the `APLPresenter.initialize()` static method before inflating the `APLLayout` UI component. The following code shows how to use the `onCreate` method of `Activity` to initialize the APL runtime: + +```java +import com.amazon.apl.android.render.APLPresenter; + +//--------------------------------------------------------------------- +// Initialize the APL Runtime. This must be called during +// Activity.onCreate() or prior to APLLayout inflation. +//--------------------------------------------------------------------- +onCreate() { + Context context = getApplicationContext(); + APLPresenter.initialize(context); +} +``` + +### Implementing the Event Interface + +The application must implement the `com.amazon.apl.android.render.interfaces.IAPLEventSender` interface. The `IAPLEventSender` interface provides the APIs to allow the APL Render module to report events to Alexa or the capability agent. You can integrate the event interface into the APL handler that implements the [Auto SDK APL platform interface](../../../../../../modules/apl/android/src/main/java/com/amazon/aace/apl/APL.java). The following code shows how to do the integration: + +```java +import com.amazon.aace.apl.APL; +import com.amazon.apl.android.render.interfaces.IAPLEventSender; + +public class APLHandler extends APL implements IAPLEventSender { + + //--------------------------------------------------------------------- + // Override IAPLEventSender methods. + // APLHandler will register with APL Render library as the event sender. + //--------------------------------------------------------------------- + @Override + public void sendRenderDocumentResult(String token, boolean result, String error) { + renderDocumentResult(token, result, error); // APL::renderDocumentResult + } + + @Override + public void sendExecuteCommandsResult(String token, boolean result, String error) { + executeCommandsResult(token, result, error); // APL::executeCommandsResult + } + + ... +} + +``` + +### Instantiating APLPresenter + +The application must instantiate the `APLPresenter` object, which provides the orchestration logic in the APL rendering process. + +>**Note:** Create `APLPresenter` *after* the APL platform interface handler is registered with the Auto SDK Engine. + +The following code shows how to instantiate the `APLPresenter` object: + +```java +import com.amazon.apl.android.render.APLPresenter; + +public class APLHandler extends APL implements IAPLEventSender { + + private APLPresenter mPresenter; + + public void buildAPLPresenter(JSONArray visualCharacteristics, String defaultWindowId) { + //--------------------------------------------------------------------- + // Retrieve the APLLayout view with id 'apl' defined in apl_view.xml. + // This assumes that 'activity' is the application's Activity. + //--------------------------------------------------------------------- + aplLayout = activity.findViewById(R.id.apl); + //--------------------------------------------------------------------- + // Application needs to handle the correlation of window ids from the + // visual characteristics configuration to the APLLayout instance. + //--------------------------------------------------------------------- + HashMap aplLayouts = new HashMap(); + aplLayouts.put(defaultWindowId, mAplLayout); + //--------------------------------------------------------------------- + // Create APLPresenter to handle APL rendering. + //--------------------------------------------------------------------- + mPresenter = new APLPresenter(aplLayouts, visualCharacteristics, defaultWindowId, this); + } +``` + +The following list describes the parameters to `APLPresenter`: + +* The first parameter is a map of the `APLLayout` objects. Each `APLLayout` is identified by a window ID, which specifies the window where the APL document is rendered. Typically, there is one `APLLayout` defined for the window where all the APL documents are rendered, but you can build skills that support rendering in multiple windows. + +* The second parameter is a JSON array` pointing to the visual characteristics defined by the device. For more information about visual characteristics, see the [APL module README](../../../../../../modules/apl/README.md#visual-characteristics) and the [Smart Screen SDK documentation](https://github.com/alexa/alexa-smart-screen-sdk/blob/master/modules/GUI/config/SmartScreenSDKConfig.md#visual-characteristics-parameters). + +* The third parameter is the default window ID, specifying the window where APL documents are rendered if Alexa does not provide a window ID. + +* The last parameter is the object that implements the `IAPLEventSender` interface. + +## Rendering an APL Document + +To render an APL document, call the `onRenderDocument` API on the `APLPresenter`. The `APLHandler` can delegate the `APL` APIs to the `APLPresenter`, as shown in the following code: + +```java +public class APLHandler extends APL implements IAPLEventSender { + + ... + + //--------------------------------------------------------------------- + // Override Auto SDK APL interfaces + //--------------------------------------------------------------------- + @Override + public void renderDocument(String payload, String token, String windowId) { + mAplPresenter.onRenderDocument(payload, token, windowId); // APLRender implements these interfaces + } + + @Override + public void executeCommands(String payload, String token) { + mPresenter.onExecuteCommands(payload, token); + } + + ... +} +``` + +## Overriding Android View Host Options + +Rendering an APL document requires the APL Render module to set up an `APLOptions` object, which is passed to the view host. The `APLOptions` object is configured with providers, callbacks, and listeners, as described in the following list: + +* Providers are objects implemented outside the view host.They provide objects used during the rendering process. For example, the data retriever provider downloads APL resources, such as layouts from content delivery networks (CDNs). The media player provider plays media, such as videos. + +* Callbacks are interfaces used by the view host to report events, such as: + + * user events (e.g., button clicks) + * document lifecycle events (e.g., completion of document rendering) + +* Listeners are interfaces for reporting the APL rendered document state or screen lock events. + +The APL Render module sets up all the providers, callbacks, and listeners. If the application needs to override any of them, it uses the `APLOptions.Builder` object. + +### Using APLOptions.Builder + +To override `APLOptions`, extend the `APLPresenter` object, as shown in the following code: + +```java +class MyAPLPresenter extends APLPresenter { + + //--------------------------------------------------------------------- + // IAPLOptionsBuilderProvider override + //--------------------------------------------------------------------- + @Override + APLOptions.Builder getAPLOptionsBuilder() { + APLOptions.Builder builder = super.getAPLOptionsBuilder(); + // Listen in on APL finish callback + builder.onAplFinishCallback(() -> { + // Do something here + super.onAplFinish(); + }); + return builder; + } +} +``` +## APL Runtime Properties + +The [IAPLContentListener](src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java) exposes an interface to control some APL runtime properties that affect how APL documents are rendered. The `onAPLRuntimeProperties` API takes in a JSON string that contains one or more properties to update. + +### Driving State + +The `drivingState` property supports the values `moving` and `parked`. An APL experience may differ depending on the driving state in order to provide a safer driving experience. + +### Theme + +The `theme` property allows the APL experience to render in different color schemes. There are six supported values: light, light-gray1, light-gray2, dark, dark-black, dark-gray. The light themes can be during for day driving, while the dark themes can be used for night driving. +## APL Extensions +### Backstack + +This library supports the [Backstack](https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-ext-backstack.html) extension. The application must ensure that the `APLPresenter` is not destroyed and recreated when a new APL document with the same token id is received. Otherwise, the Backstack will be reinstantiated and the previous stack of documents will be lost. + +### Local Information Data + +This library contains a custom APL extension that is used by the `APLPresenter` to expose point of interest data to the application. This data can be used to drop corresponding pins on the head unit's integrated map. Two way communication is also provided so that the application or AP runtime can notify each other when a specific data point is active or selected. + +There are two interfaces that the application can use to interact with Local infomation data: [ILocalInfoDataConsumer](https://github.com/alexa/alexa-auto-sdk/tree/4.0/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataConsumer.java) and [ILocalInfoDataReporter](https://github.com/alexa/alexa-auto-sdk/tree/4.0/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataReporter.java). + +#### ILocalInfoDataConsumer + +The [IPresenter](src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java) interace exposes a method to set the data consumer, which must be set by the application: + +``` + /** + * Saves a reference to the local info data consumer. + * + * @param consumer The object that consume local info data events. + */ + void setLocalInfoDataConsumer(ILocalInfoDataConsumer consumer); +``` + +The application will be notified through the consumer method `aplDataAvailable` with a JSON string object represention all the points of interest. The application will be notified when a specific data point is selected on the APL document using the consume method `aplDataItemSelectedById`. + +#### ILocalInfoDataReporter + +The `APLPresenter` implements the `ILocalInfoDataReporter` interface to allow the application to notify the APL runtime when a data point is selected outside of the APL runtime. To do this notification simply call `platformDataItemSelectedById` on the `APLPresenter` instance. + +## Building the APL Render Library +**Note:** Before proceeding to build the APL Render library, download the Android APL resource from the developer portal according to instructions from your Solutions Architect or Partner Manager. + +This library can be built using the included gradle wrapper as follows +``` +./gradlew assembleRelease +``` \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/build.gradle b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/build.gradle new file mode 100644 index 000000000..408a7fc80 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/build.gradle @@ -0,0 +1,74 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 22 + targetSdkVersion 28 + versionCode 1 + versionName "4.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + // Enable desugaring (dependency contains Java 8 bytecode) + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + + lintOptions { + abortOnError false + } +} + +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +dependencies { + compileOnly files('src/main/libs/aplRelease.aar') + compileOnly files('src/main/libs/ttsplayerRelease.aar') + + implementation 'androidx.media:media:1.3.0' + implementation 'androidx.appcompat:appcompat:1.0.0' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.annotation:annotation:1.0.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.cardview:cardview:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3' + implementation 'com.google.android.exoplayer:exoplayer-dash:2.13.3' + implementation 'com.google.android.exoplayer:exoplayer-smoothstreaming:2.13.3' + implementation 'com.google.android.exoplayer:exoplayer-hls:2.13.3' + implementation 'com.google.android.gms:play-services-maps:16.0.0' + implementation 'com.github.bumptech.glide:glide:4.11.0' + implementation 'androidx.fragment:fragment:1.2.4' + implementation 'com.squareup.okhttp3:okhttp:3.9.1' + implementation 'com.google.dagger:dagger:2.33' + implementation 'org.projectlombok:lombok:1.18.18' + implementation 'com.google.guava:guava:27.0.1-android' + + annotationProcessor 'com.google.dagger:dagger-compiler:2.33' + annotationProcessor 'org.projectlombok:lombok:1.18.18' + +} diff --git a/platforms/android/modules/apl-render/gradle.properties b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/gradle.properties similarity index 100% rename from platforms/android/modules/apl-render/gradle.properties rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/gradle.properties diff --git a/platforms/android/modules/apl-render/lombok.config b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/lombok.config similarity index 100% rename from platforms/android/modules/apl-render/lombok.config rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/lombok.config diff --git a/extensions/bluetooth/samples/android/modules/sample-bluetooth/proguard-rules.pro b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/proguard-rules.pro similarity index 100% rename from extensions/bluetooth/samples/android/modules/sample-bluetooth/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/proguard-rules.pro diff --git a/platforms/android/modules/apl-render/settings.gradle b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/settings.gradle similarity index 100% rename from platforms/android/modules/apl-render/settings.gradle rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/settings.gradle diff --git a/platforms/android/modules/apl-render/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/modules/apl-render/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/AndroidManifest.xml diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLPresenter.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLPresenter.java new file mode 100644 index 000000000..05dbf4c59 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLPresenter.java @@ -0,0 +1,807 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render; + +import android.content.Context; +import android.util.Log; +import android.view.KeyEvent; +import android.view.MotionEvent; + +import androidx.annotation.NonNull; +import androidx.core.util.Preconditions; + +import com.amazon.apl.android.APLController; +import com.amazon.apl.android.APLLayout; +import com.amazon.apl.android.APLOptions; +import com.amazon.apl.android.Action; +import com.amazon.apl.android.Content; +import com.amazon.apl.android.IAPLViewPresenter; +import com.amazon.apl.android.RootConfig; +import com.amazon.apl.android.RootContext; +import com.amazon.apl.android.RuntimeConfig; +import com.amazon.apl.android.configuration.ConfigurationChange; +import com.amazon.apl.android.dependencies.IDataSourceErrorCallback; +import com.amazon.apl.android.dependencies.IDataSourceFetchCallback; +import com.amazon.apl.android.dependencies.ISendEventCallback; +import com.amazon.apl.android.dependencies.IVisualContextListener; +import com.amazon.apl.android.render.content.APLHttpContentRetriever; +import com.amazon.apl.android.render.dagger.component.ActivityComponent; +import com.amazon.apl.android.render.dagger.component.ApplicationComponent; +import com.amazon.apl.android.render.dagger.component.DaggerActivityComponent; +import com.amazon.apl.android.render.dagger.module.ActivityModule; +import com.amazon.apl.android.render.extension.ExtensionManager; +import com.amazon.apl.android.render.extension.back.BackExtension; +import com.amazon.apl.android.render.extension.back.BackStack; +import com.amazon.apl.android.render.extension.back.BackStackDocument; +import com.amazon.apl.android.render.extension.localinfo.LocalInfoExtension; +import com.amazon.apl.android.render.font.AutoEmbeddedFontResolver; +import com.amazon.apl.android.render.interfaces.IAPLContentListener; +import com.amazon.apl.android.render.interfaces.IAPLEventSender; +import com.amazon.apl.android.render.interfaces.IAPLTokenProvider; +import com.amazon.apl.android.render.interfaces.IDismissible; +import com.amazon.apl.android.render.interfaces.ILocalInfoDataConsumer; +import com.amazon.apl.android.render.interfaces.ILocalInfoDataReporter; +import com.amazon.apl.android.render.interfaces.IPresenter; +import com.amazon.apl.android.render.payload.ExecuteCommandPayload; +import com.amazon.apl.android.render.payload.RenderDocumentPayload; +import com.amazon.apl.android.render.payload.RenderedDocumentStatePayload; +import com.amazon.apl.android.render.payload.UserEventPayload; +import com.amazon.apl.android.render.utils.RenderDocumentUtils; +import com.amazon.apl.android.scaling.Scaling; +import com.amazon.apl.enums.ViewportMode; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * This class facilitates the integration of Alexa Presentation Language (APL). + * The application is required to initialize the APL runtime by passing the Android + * context to @see initialize(context) prior to the inflation of @see APLLayout components. + * The visual configuration is used to provide window state context. + */ +public class APLPresenter implements IPresenter, ISendEventCallback, IDataSourceFetchCallback, IDataSourceErrorCallback, + IVisualContextListener, IAPLTokenProvider, ILocalInfoDataReporter { + private static final String TAG = APLPresenter.class.getSimpleName(); + + private IAPLEventSender mAplEventSender; + private Map mAplLayouts; + private Action mAction; + private APLController mAplController; + private String mToken; + private APLOptions mAplOptions; + private ActivityComponent mActivityComponent; + private ApplicationComponent mApplicationComponent; + private RenderDocumentPayload mRenderDocumentPayload; + private RenderedDocumentStatePayload mLatestRenderedDocumentState; + private String mDefaultWindowId; + private JSONArray mVisualCharacteristics; + private Hashtable mRuntimeProperties; + private ExtensionManager mExtensionManager; + private LocalInfoExtension mLocalInfoExtension; + private BackExtension mBackHandler; + private BackStack mBackStack; + private ILocalInfoDataConsumer mLocalInfoDataConsumer; + private IDismissible mDismissibleCallback; + + private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(); + private static Context mContext; + private RootConfig mRootConfig; + + /** + * Initialize the APL runtime. Must be done during Activity onCreate or + * prior to inflation of APLLayout view. + * + * @param context + */ + public static void initialize(Context context) { + mContext = context; + APLController.initializeAPL( + context, RuntimeConfig.builder().fontResolver(new AutoEmbeddedFontResolver(context)).build()); + } + + /** + * Constructs the APLPresenter object. + * + * @param aplLayouts A map of windows ids to the corresponding APL layouts. + * @param visualCharacteristics The array of defined visual characteristics for the device. + * @param defaultWindowId The Id of the window where APL will be rendered if one is not specified in the render + * document request. + * @param aplEventSender The object used to send events back to the cloud. + */ + public APLPresenter(@NonNull final Map aplLayouts, @NonNull JSONArray visualCharacteristics, + @NonNull String defaultWindowId, @NonNull final IAPLEventSender aplEventSender) + throws IllegalStateException { + // Initialize must be called prior to instantiation of this class. + if (mContext == null) { + throw new IllegalStateException("Context is null. Make sure initialize() is called with non null context."); + } + + Preconditions.checkNotNull(aplLayouts); + Preconditions.checkNotNull(visualCharacteristics); + Preconditions.checkNotNull(defaultWindowId); + Preconditions.checkState(!defaultWindowId.isEmpty()); + Preconditions.checkNotNull(aplEventSender); + + mAplLayouts = aplLayouts; + mVisualCharacteristics = visualCharacteristics; + mAplEventSender = aplEventSender; + mDefaultWindowId = defaultWindowId; + APLSingleton.getInstance().init(mContext, mAplEventSender, this); + mApplicationComponent = APLSingleton.getInstance().getApplicationComponent(); + mActivityComponent = initActivityComponent(mContext); + mBackStack = new BackStack(); + + // Default property values + mRuntimeProperties = new Hashtable<>(); + mRuntimeProperties.put("drivingState", "moving"); + mRuntimeProperties.put("theme", "dark"); + mRuntimeProperties.put("video", "disabled"); + + // Initial window state + sendDeviceWindowState(); + + // Listen for touch events + setupTouchListener(); + } + + private synchronized void updateRuntimeProperties() { + Log.v(TAG, "updateRuntimeProperties" + mRuntimeProperties.toString()); + if (mAplController != null) { + APLLayout aplLayout = getAplLayout(); + if (aplLayout != null) { + aplLayout.post(() -> { + Map autoEnvironmentValues = new HashMap<>(); + autoEnvironmentValues.put("drivingState", mRuntimeProperties.get("drivingState")); + ConfigurationChange configurationChange = + aplLayout.createConfigurationChange() + .theme(mRuntimeProperties.get("theme")) + .disallowVideo(mRuntimeProperties.get("video").equalsIgnoreCase("disabled")) + .environmentValue("automobile", autoEnvironmentValues) + .build(); + try { + aplLayout.handleConfigurationChange(configurationChange); + Log.v(TAG, "onConfigChange succeeded"); + } catch (Exception e) { + Log.e(TAG, "Document cannot be rendered in this configuration", e); + } + }); + } + } + } + + //------------------------------------------------------------------------- + // IAPLContentListener + //------------------------------------------------------------------------- + + /** + * Application will notify of APL content through this listener. Content includes + * render document payload, execute commands, data source updates, etc. + * + * @return IAPLContentListener The object that listens for APL content. + */ + public IAPLContentListener getAPLContentListener() { + return this; + } + + /** + * Handle updates from the vehicle that affect how the APL document + * should be rendered. + * + * @param properties JSON string containing one or more properties. + */ + @Override + public void onAPLRuntimeProperties(String properties) { + try { + JSONObject propertiesObject = new JSONObject(properties); + if (propertiesObject.has("drivingState")) { + mRuntimeProperties.put("drivingState", propertiesObject.getString("drivingState").toLowerCase()); + } + + if (propertiesObject.has("theme")) { + mRuntimeProperties.put("theme", propertiesObject.getString("theme").toLowerCase()); + } + + if (propertiesObject.has("video")) { + mRuntimeProperties.put("video", propertiesObject.getString("video").toLowerCase()); + } + + updateRuntimeProperties(); + } catch (JSONException e) { + Log.e(TAG, "propertiesJSONError"); + } + } + + @Override + public void onRenderDocument(String jsonPayload, String token, String windowId) { + try { + mToken = token; + // Extract document and data + mRenderDocumentPayload = RenderDocumentUtils.convertToRenderDocument(jsonPayload); + mRootConfig = mActivityComponent.getRootConfig(); + + Log.i(TAG, "APL render document token: " + mToken + " windowId: " + mRenderDocumentPayload.getWindowId()); + + // Set up content retriever and render callback + APLHttpContentRetriever contentRetriever = + new APLHttpContentRetriever(mApplicationComponent.getOkHttpClientWrapper(), + mApplicationComponent.getNetworkExecutor(), mRenderDocumentPayload); + contentRetriever.addCompleteCallback(content -> doRender(content)); + + // Inflate the document + try { + Content.create(mRenderDocumentPayload.getDocument(), contentRetriever); + } catch (Content.ContentException exception) { + Log.e(TAG, exception.getMessage()); + } + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + renderResponse(token, false, e.getMessage()); + } + } + + @Override + public void onClearDocument(String token) { + Log.i(TAG, "clearDocument and visual context " + token + " mToken: " + mToken); + getAplLayout().post(() -> { + // Clean up current view + destroyAplView(); + // Clear back stack since skill session is done + mBackStack.clear(); + // Notify that clear document is done + mExecutor.submit(() -> { + Log.i(TAG, "Clearing card: token: " + token); + mLatestRenderedDocumentState = null; + mRenderDocumentPayload = null; + mToken = null; + sendDeviceWindowState(); + mAplEventSender.sendClearCard(); + }); + }); + } + + @Override + public void onExecuteCommands(String payload, String token) { + mToken = token; + getAplLayout().post(() -> { + try { + // Log payload and token + Log.v(TAG, "onExecuteCommands: payload: " + payload); + ExecuteCommandPayload commandPayload = ExecuteCommandPayload.convertToExecuteCommand(payload); + String commandsString = commandPayload.getCommands(); + if (!commandsString.isEmpty()) { + mAplController.executeCommands(commandsString, action -> { + if (action != null) { + action.then(() -> { + Log.i(TAG, + "onExecuteCommands: result: true command: token:" + token + + " command: " + commandsString); + mAplEventSender.sendExecuteCommandsResult(token, true, ""); + // Inactive after command completion + mAplEventSender.sendActivityEventRequest( + token, IAPLEventSender.ActivityEvent.DEACTIVATED); + }); + action.addTerminateCallback(() -> { + Log.e(TAG, "onExecuteCommands: result: false token: " + token + " command terminated"); + mAplEventSender.sendExecuteCommandsResult(token, false, "Missing commands"); + // Inactive after command termination + mAplEventSender.sendActivityEventRequest( + token, IAPLEventSender.ActivityEvent.DEACTIVATED); + }); + // Active while commands run + mAplEventSender.sendActivityEventRequest(token, IAPLEventSender.ActivityEvent.ACTIVATED); + } + }); + } else { + mExecutor.submit(() -> { + Log.e(TAG, "onExecuteCommands: result: false token: " + token); + mAplEventSender.sendExecuteCommandsResult(token, false, "Missing commands"); + }); + } + } catch (Exception e) { + Log.e(TAG, "onExecuteCommands: token: result: false token: " + token + " error: " + e.getMessage()); + mExecutor.submit(() -> { mAplEventSender.sendExecuteCommandsResult(token, false, e.getMessage()); }); + } + }); + } + + @Override + public void onDataSourceUpdate(String sourceType, String payload, String token) { + Log.i(TAG, "dataSourceUpdate called: " + sourceType + " payload: " + payload + " token: " + token); + // Update data in APL Controller + if (!mAplController.updateDataSource(sourceType, payload)) { + Log.e(TAG, "handleDataSourceFetchRequest: updateDataSource was unsuccessful"); + } + } + + @Override + public void onInterruptCommandSequence(String token) { + getAplLayout().post(() -> { + try { + Log.i(TAG, "Interrupting command sequence"); + mAplController.cancelExecution(); + } catch (Exception e) { + Log.e(TAG, "Interrupting command sequence did not succeed: " + e.getMessage()); + } + }); + } + + //------------------------------------------------------------------------- + // IAPLOptionsBuilderProvider + //------------------------------------------------------------------------- + + @NonNull + @Override + public APLOptions.Builder getAPLOptionsBuilder() { + return mActivityComponent.getAPLOptionsBuilder() + .sendEventCallback(this) + .dataSourceFetchCallback(this) + .dataSourceErrorCallback(this) + .onAplFinishCallback(this) + .extensionEventCallback(mExtensionManager) + .visualContextListener(this); + } + + //------------------------------------------------------------------------- + // IAPLEventSender + //------------------------------------------------------------------------- + + @Override + public IAPLEventSender getAplEventSender() { + return mAplEventSender; + } + + //------------------------------------------------------------------------- + // IAPLTokenProvider + //------------------------------------------------------------------------- + + @Override + public String getToken() { + return mToken; + } + + //------------------------------------------------------------------------- + // IVisualContextListener - Android Viewhost + //------------------------------------------------------------------------- + + @Override + public void onVisualContextUpdate(JSONObject visualContext) { + Log.v(TAG, "Visual context update: " + visualContext); + + if (mRenderDocumentPayload != null) { + JSONArray compsVisibleOnScreen = new JSONArray(); + compsVisibleOnScreen.put(visualContext); + RenderedDocumentStatePayload payload = + RenderedDocumentStatePayload.builder() + .presentationToken(mRenderDocumentPayload.getPresentationToken()) + .presentationSession(mRenderDocumentPayload.getPresentationSession()) + .versionName(BuildConfig.VERSION_NAME) + .componentsVisibleOnScreenArray(compsVisibleOnScreen) + .build(); + mLatestRenderedDocumentState = payload; + mAplEventSender.sendContext(mLatestRenderedDocumentState.toString()); + } + } + + //------------------------------------------------------------------------- + // IPresenter + //------------------------------------------------------------------------- + + @Override + public void onTouchEvent(MotionEvent event) { + Log.v(TAG, "onTouchEvent: " + event); + String token = getToken(); + if (token != null) { + mAplEventSender.sendActivityEventRequest(token, IAPLEventSender.ActivityEvent.ONE_TIME); + } + } + + @Override + public boolean onKeyEvent(KeyEvent event) { + Log.v(TAG, "onKeyEvent: " + event); + String token = getToken(); + if (token != null) { + mAplEventSender.sendActivityEventRequest(token, IAPLEventSender.ActivityEvent.ONE_TIME); + } + return false; + } + + @Override + public APLLayout getAplLayout() { + String windowId = mRenderDocumentPayload != null && !mRenderDocumentPayload.getWindowId().isEmpty() + ? mRenderDocumentPayload.getWindowId() + : mDefaultWindowId; + return mAplLayouts.get(windowId); + } + + @Override + public void setLocalInfoDataConsumer(ILocalInfoDataConsumer consumer) { + mLocalInfoDataConsumer = consumer; + } + + @Override + public void setDismissibleCallback(IDismissible dismissibleCallback) { + mDismissibleCallback = dismissibleCallback; + } + + @Override + public void cancelExecution() { + if (mAplController != null) { + Log.i(TAG, "cancelExecution"); + mAplController.cancelExecution(); + } + } + + /** + * The following overrides are for methods defined by interfaces in the + * Android viewhost. + */ + + //------------------------------------------------------------------------- + // IOnAplFinishCallback - Android Viewhost + //------------------------------------------------------------------------- + + @Override + public void onAplFinish() { + Log.v(TAG, "APL Rendering finished"); + if (mDismissibleCallback != null) { + mDismissibleCallback.onDismiss(); + } + } + + //------------------------------------------------------------------------- + // ISendEventCallback - Android Viewhost + //------------------------------------------------------------------------- + + @Override + public void onSendEvent(Object[] args, Map components, Map sources) { + try { + JSONArray jsonArgs = new JSONArray((args)); + JSONObject jsonComponents = new JSONObject(components); + JSONObject jsonSources = new JSONObject(sources); + + String userEvent = new UserEventPayload(getToken(), jsonArgs, jsonComponents, jsonSources).toString(); + Log.v(TAG, "UserEvent: " + userEvent); + mAplEventSender.sendUserEventRequest(userEvent); + } catch (Exception e) { + Log.e(TAG, e.getMessage()); + } + } + + //------------------------------------------------------------------------- + // IDataSourceErrorCallback - Android Viewhost + //------------------------------------------------------------------------- + + @Override + public void onDataSourceError(Object errors) { + JSONObject payload = new JSONObject(); + try { + final JSONArray errorsJson = new JSONArray(errors); + payload.put("errors", errorsJson); + payload.put("presentationToken", getToken()); + + Log.v(TAG, "onDataSourceError: " + payload.toString()); + // Notify that an error occurred + mAplEventSender.sendRuntimeErrorEventRequest(payload.toString()); + } catch (JSONException e) { + Log.e(TAG, "Exception occurred while preparing RuntimeError Event payload", e); + } + } + + //------------------------------------------------------------------------- + // IDataSourceFetchCallback - Android Viewhost + //------------------------------------------------------------------------- + + @Override + public void onDataSourceFetchRequest(String dataSourceType, Map eventPayload) { + if (dataSourceType == null) { + Log.e(TAG, "onDataSourceFetchRequest: dataSource type is null"); + return; + } + + if (eventPayload == null) { + Log.e(TAG, "onDataSourceFetchRequest: eventPayload type is null"); + return; + } + + // Construct data source fetch request payload + JSONObject payload; + payload = new JSONObject(eventPayload); + try { + payload.put("presentationToken", getToken()); + Log.i(TAG, "onDataSourceFetchRequest: " + dataSourceType + " payload: " + payload.toString()); + // Notify that event should be sent + mAplEventSender.sendDataSourceFetchEventRequest(dataSourceType, payload.toString()); + + } catch (JSONException e) { + Log.e(TAG, "onDataSourceFetchRequest: unable to add presentation token", e); + } + } + + //------------------------------------------------------------------------- + // IDocumentLifecycleListener - Android Viewhost + //------------------------------------------------------------------------- + + @Override + public void onDocumentRender(@NonNull RootContext rootContext) { + Log.v(TAG, "onDocumentRender: "); + renderResponse(getToken(), true, ""); + } + + @Override + public void onDocumentFinish() { + Log.v(TAG, "onDocumentFinish: "); + } + + //------------------------------------------------------------------------- + // ILocalInfoDataReporter + //------------------------------------------------------------------------- + + @Override + public void platformDataItemSelectedById(String poiId) { + if (mLocalInfoExtension != null) { + Log.v(TAG, "poiSelected " + poiId); + mLocalInfoExtension.poiSelected(mAplController, poiId); + mAplEventSender.sendActivityEventRequest(mToken, IAPLEventSender.ActivityEvent.ONE_TIME); + } + } + + //------------------------------------------------------------------------- + // Helper private methods + //------------------------------------------------------------------------- + + /** + * Returns the APL options that will be used in rendering document. + * + * @return APLOptions The options used for rendering. + */ + private synchronized APLOptions getAPLOptions() { + if (mAplOptions == null) { + mAplOptions = getAPLOptionsBuilder().build(); + } + return mAplOptions; + } + + /** + * Initialize the activity component object that provides APL options and configuration. + * + * @param context + * @return ActivityComponent The activity component object. + */ + private ActivityComponent initActivityComponent(Context context) { + return DaggerActivityComponent.builder() + .activityModule(new ActivityModule(context)) + .applicationComponent(mApplicationComponent) + .build(); + } + + /** + * Listen for touch events on the APL layout so that + * we can report activity events to prevent document from + * timing out when there is user interaction. + */ + private void setupTouchListener() { + for (APLLayout aplLayout : mAplLayouts.values()) { + aplLayout.setOnTouchListener((view, event) -> { + if (event.getAction() == MotionEvent.ACTION_UP) { + onTouchEvent(event); + aplLayout.performClick(); + } + + // Let the parent consume the event + return false; + }); + } + } + + /** + * Render the document. + * + * @param content the inflated contents + */ + private void doRender(Content content) { + // Finish the old document + destroyAplView(); + applyScaling(); + + mExtensionManager = new ExtensionManager(mRootConfig); + Set extensionRequests = content.getExtensionRequests(); + + mBackHandler = new BackExtension(mBackStack, this::goBack, this); + mBackHandler.setResponsibleForBackButton(true); + mExtensionManager.addBuiltInExtension(mBackHandler); + + Map extensionSettings = content.getExtensionSettings(mBackHandler.getUri()); + if (extensionSettings != null) { + Object backstackSettings = extensionSettings.get(BackExtension.SETTINGS_PROPERTY_BACKSTACK_ID); + if (backstackSettings != null) { + mBackHandler.setDocumentId(backstackSettings.toString()); + } + } + + if (extensionRequests.contains(LocalInfoExtension.URI)) { + mLocalInfoExtension = new LocalInfoExtension(mRootConfig); + mLocalInfoExtension.setDataConsumer(mLocalInfoDataConsumer); + mExtensionManager.addBuiltInExtension(mLocalInfoExtension); + } + + // Register extension and render when done + mExtensionManager.registerRequestedExtensions(extensionRequests, () -> performLayout(content)); + } + + private void performLayout(Content content) { + // Make sure mAplLayout is inflated and initialized + APLLayout aplLayout = getAplLayout(); + APLOptions options = getAPLOptions(); + + try { + aplLayout.post(() -> { + IAPLViewPresenter presenter = aplLayout.getPresenter(); + aplLayout.getPresenter().addDocumentLifecycleListener(this); + try { + mAplController = APLController.renderDocument(content, options, mRootConfig, presenter); + sendDeviceWindowState(); + updateRuntimeProperties(); + } catch (Exception e) { + Log.e(TAG, "Cannot render ", e); + renderResponse(getToken(), false, e.getMessage()); + } + }); + + } catch (Exception e) { + Log.e(TAG, "Render failed", e); + } + } + + private void renderResponse(String token, boolean result, String message) { + mExecutor.submit(() -> { + Log.i(TAG, "Render document result: " + result + " token: " + token + " message: " + message); + mAplEventSender.sendRenderDocumentResult(token, result, message); + }); + } + + /** + * Clean up rendering session. + */ + private synchronized void destroyAplView() { + if (mAplController == null) { + return; + } else { + if (mBackHandler != null) { + BackStackDocument document = + new BackStackDocument(mBackHandler.getDocumentId(), mAplController.getDocumentState()); + mBackHandler.addDocument(document); + } + } + + mLocalInfoExtension = null; + mExtensionManager = null; + mAplController.finishDocument(); + mAplController = null; + mAction = null; + } + + /** + * Set the scaling based on the supported view ports. + */ + private void applyScaling() { + List fallbackModes = Collections.singletonList(ViewportMode.kViewportModeAuto); + List viewportSpecifications = mRenderDocumentPayload.getViewportSpecifications(); + Log.v(TAG, "viewportSpecification: " + viewportSpecifications.toString()); + Scaling scaling = viewportSpecifications.isEmpty() ? new Scaling() + : new Scaling(10.0, viewportSpecifications, fallbackModes); + + // Apply the scaling + getAplLayout().setScaling(scaling); + } + + /** + * Builds the initial device window state that will be reported after + * platform interface registration. + * { + * "defaultWindowId": "string", + * "instances" : [ + * { + * "id": "string", + * "templateId": "string", + * "token" : "", + * "configuration": { + * "interactionMode": "string", + * "sizeConfigurationId": "string" + * } + * } + * ] + * } + * + */ + private void sendDeviceWindowState() { + JSONObject deviceWindowState = new JSONObject(); + JSONArray windowInstances = new JSONArray(); + String windowId = mRenderDocumentPayload != null && !mRenderDocumentPayload.getWindowId().isEmpty() + ? mRenderDocumentPayload.getWindowId() + : mDefaultWindowId; + String token = getToken(); + + try { + if (mVisualCharacteristics.length() > 0) { + for (int i = 0; i < mVisualCharacteristics.length(); i++) { + JSONObject currentElement = mVisualCharacteristics.getJSONObject(i); + if (currentElement.getString("interface").equals("Alexa.Display.Window")) { + JSONArray templates = currentElement.getJSONObject("configurations").getJSONArray("templates"); + for (int j = 0; j < templates.length(); j++) { + JSONObject template = templates.getJSONObject(j); + JSONObject windowInstance = new JSONObject(); + JSONObject windowConfiguration = new JSONObject(); + JSONObject configuration = template.getJSONObject("configuration"); + String templateId = template.getString("id"); + + windowInstance.put("id", templateId); + windowInstance.put("templateId", templateId); + windowInstance.put("token", ""); + + // Token must on the rendering window + if (windowId.equals(templateId)) { + windowInstance.put("token", token); + } + + windowConfiguration.put( + "interactionMode", configuration.getJSONArray("interactionModes").getString(0)); + windowConfiguration.put("sizeConfigurationId", + configuration.getJSONArray("sizes").getJSONObject(0).getString("id")); + windowInstance.put("configuration", windowConfiguration); + + windowInstances.put(windowInstance); + } + } + } + + deviceWindowState.put("defaultWindowId", mDefaultWindowId); + deviceWindowState.put("instances", windowInstances); + + Log.v(TAG, "deviceWindowState: " + deviceWindowState.toString()); + mAplEventSender.sendWindowState(deviceWindowState.toString()); + } + } catch (JSONException e) { + Log.e(TAG, "Unable to build window state", e); + } + } + + //------------------------------------------------------------------------- + // BackStack Support + //------------------------------------------------------------------------- + + public void goBack(@NonNull BackStackDocument backStackDocument) { + getAplLayout().post(() -> { + mAplController.finishDocument(); + backStackDocument.getDocumentState().setOptions(getAPLOptions()); + try { + mAplController = APLController.restoreDocument( + backStackDocument.getDocumentState(), getAplLayout().getPresenter()); + } catch (APLController.APLException e) { + Log.e(TAG, "Document failed to restore."); + } + }); + } +} diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java similarity index 97% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java index 6368db56d..5fb44db1a 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/APLSingleton.java @@ -37,7 +37,7 @@ public class APLSingleton { // Since Java loads the fields in declaration order, place this at the top. private static final long INIT_TIME = System.currentTimeMillis(); - private static final String TAG = "APLSingleton"; + private static final String TAG = APLSingleton.class.getSimpleName(); private static final APLSingleton INSTANCE = new APLSingleton(); diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/audio/AudioFocusController.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/audio/AudioFocusController.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/audio/AudioFocusController.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/audio/AudioFocusController.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java similarity index 98% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java index bef7d2b12..3fd00fc8f 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/content/APLHttpContentRetriever.java @@ -25,7 +25,7 @@ * resources such as packages, layouts, media, etc. */ public class APLHttpContentRetriever extends Content.Callback { - private static final String TAG = "OkHttpAssetContentCallb"; + private static final String TAG = APLHttpContentRetriever.class.getSimpleName(); public static final String CLOUDFRONT_LOCATION_PREFIX = "https://d2na8397m465mh.cloudfront.net/packages/"; private static final String CLOUDFRONT_LOCATION_SUFFIX = "/document.json"; diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityContext.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityContext.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityContext.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityContext.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityScope.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityScope.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityScope.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ActivityScope.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationContext.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationContext.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationContext.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationContext.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationScope.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationScope.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationScope.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/ApplicationScope.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ActivityComponent.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ActivityComponent.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ActivityComponent.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ActivityComponent.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ApplicationComponent.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ApplicationComponent.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ApplicationComponent.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/component/ApplicationComponent.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java similarity index 87% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java index 2b69c7c0c..4bc9efc36 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/APLOptionsModule.java @@ -16,19 +16,20 @@ package com.amazon.apl.android.render.dagger.module; import android.content.Context; -import android.view.TextureView; import com.amazon.apl.android.APLOptions; import com.amazon.apl.android.RootConfig; import com.amazon.apl.android.dependencies.IOpenUrlCallback; import com.amazon.apl.android.dependencies.impl.OpenUrlCallback; -import com.amazon.apl.android.providers.AbstractMediaPlayerProvider; import com.amazon.apl.android.render.BuildConfig; import com.amazon.apl.android.render.dagger.ActivityContext; import com.amazon.apl.android.render.dagger.ActivityScope; import com.amazon.apl.android.render.media.APLMediaPlayerProvider; import com.amazon.apl.android.render.tts.APLTtsPlayerProvider; +import java.util.HashMap; +import java.util.Map; + import dagger.Module; import dagger.Provides; @@ -64,11 +65,13 @@ public IOpenUrlCallback provideOpenUrl(@ActivityContext final Context context) { */ @Provides public RootConfig provideRootConfig(@ActivityContext final Context context) { - String[] packageVersion = BuildConfig.VERSION_NAME.split("-"); + Map autoEnvironmentValues = new HashMap<>(); + autoEnvironmentValues.put("drivingState", "moving"); return RootConfig.create(context) - .agent(packageVersion[0], packageVersion[1]) + .agent(BuildConfig.VERSION_NAME, "1.9") .registerDataSource("dynamicIndexList") .registerDataSource("dynamicTokenList") - .allowOpenUrl(true); + .setEnvironmentValue("automobile", autoEnvironmentValues) + .allowOpenUrl(false); } } diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ActivityModule.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ActivityModule.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ActivityModule.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ActivityModule.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ApplicationModule.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ApplicationModule.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ApplicationModule.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/ApplicationModule.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/MediaPlayerModule.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/MediaPlayerModule.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/MediaPlayerModule.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/MediaPlayerModule.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/NetworkModule.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/NetworkModule.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/NetworkModule.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/NetworkModule.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/TtsModule.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/TtsModule.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/TtsModule.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/dagger/module/TtsModule.java diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/ExtensionManager.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/ExtensionManager.java new file mode 100644 index 000000000..70e88c040 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/ExtensionManager.java @@ -0,0 +1,142 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.extension; + +import android.util.Log; + +import com.amazon.apl.android.Event; +import com.amazon.apl.android.ExtensionCommandDefinition; +import com.amazon.apl.android.ExtensionEventHandler; +import com.amazon.apl.android.ExtensionFilterDefinition; +import com.amazon.apl.android.RootConfig; +import com.amazon.apl.android.dependencies.IExtensionEventCallback; +import com.amazon.apl.android.providers.IExtension; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Extension Manager responsible for containing available extensions and registering requested extension + * with the root config. + */ +public class ExtensionManager implements IExtensionEventCallback { + private static final String TAG = ExtensionManager.class.getSimpleName(); + + private Map mExtensions; + private RootConfig mRootConfig; + private DiscoveryCallback mDiscoveryCallback; + + //------------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------------- + + public ExtensionManager(RootConfig rootConfig) { + mRootConfig = rootConfig; + mExtensions = new HashMap<>(); + } + + private IExtension getBuiltInExtension(String uri) { + return mExtensions.get(uri); + } + + //------------------------------------------------------------------------- + // Public methods + //------------------------------------------------------------------------- + + /** + * Interface for notifying when the extensions are loaded and registered. + */ + public interface DiscoveryCallback { void onComplete(); } + + /** + * Adds a built in extension so that it is registered with the APL runtime. + * + * @param extension The extension to add. + */ + public void addBuiltInExtension(IExtension extension) { + mExtensions.put(extension.getUri(), extension); + } + + /** + * This method will register the built in extensions that are requested by the + * APL document only if they are available in the extension manager. + * + * @param requestedExtensionUris Extensions requested through the APL document. + * @param content The APL runtime content. + * @param context The Android context. + * @param discoveryCallback The callback to execute once extensions are registered. + */ + public void registerRequestedExtensions(Set requestedExtensionUris, DiscoveryCallback discoveryCallback) { + mDiscoveryCallback = discoveryCallback; + + for (String requestedExtensionUri : requestedExtensionUris) { + IExtension extension = getBuiltInExtension(requestedExtensionUri); + if (extension != null) { + Log.v(TAG, "Registering extension: " + requestedExtensionUri); + mRootConfig.registerExtensionEnvironment(extension.getUri(), extension.getEnvironment()); + for (ExtensionCommandDefinition command : extension.getCommandDefinitions()) { + mRootConfig.registerExtensionCommand(command); + } + for (ExtensionFilterDefinition filter : extension.getFilterDefinitions()) { + mRootConfig.registerExtensionFilter(filter); + } + for (ExtensionEventHandler handler : extension.getEventHandlers()) { + mRootConfig.registerExtensionEventHandler(handler); + } + } else { + Log.v(TAG, "Extension not supported by runtime: " + requestedExtensionUri); + } + } + + Log.v(TAG, "Finished registering extensions"); + mDiscoveryCallback.onComplete(); + } + + //------------------------------------------------------------------------- + // IExtensionEventCallback + //------------------------------------------------------------------------- + + @Override + public void onExtensionEvent(String name, String uri, Event event, Map source, + Map custom, IExtensionEventCallbackResult resultCallback) { + handleOnExtensionEvent(name, uri, event, source, custom, resultCallback); + } + + @Override + public void onExtensionEvent(String name, String uri, Map source, Map custom, + IExtensionEventCallbackResult resultCallback) { + handleOnExtensionEvent(name, uri, null, source, custom, resultCallback); + } + + private void handleOnExtensionEvent(String name, String uri, Event event, Map source, + Map custom, IExtensionEventCallbackResult resultCallback) { + Log.v(TAG, + "handleOnExtensionEvent uri: " + uri + " event: " + event + " source: " + source + + " custom: " + custom); + IExtension extension = getBuiltInExtension(uri); + if (extension != null) { + IExtensionEventCallback callback = extension.getCallback(); + if (callback != null) { + callback.onExtensionEvent(name, uri, event, source, custom, resultCallback); + } else { + Log.w(TAG, "Callback not handled for uri:" + uri); + } + } else { + Log.w(TAG, "Extension not found uri:" + uri); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackExtension.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackExtension.java new file mode 100644 index 000000000..a9c19c716 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackExtension.java @@ -0,0 +1,325 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.extension.back; + +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.amazon.apl.android.ExtensionCommandDefinition; +import com.amazon.apl.android.ExtensionEventHandler; +import com.amazon.apl.android.LegacyLocalExtension; +import com.amazon.apl.android.dependencies.IExtensionEventCallback; +import com.amazon.apl.android.dependencies.IOnAplFinishCallback; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Implementation of the APL BackStack extension. Allows APL documents to navigate back to previously + * rendered APL documents. + * + * APL-Spec https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-ext-backstack.html + */ +public class BackExtension extends LegacyLocalExtension { + private static final String TAG = BackExtension.class.getSimpleName(); + + public static final String URI = "aplext:backstack:10"; + public static final String COMMAND_GO_BACK_NAME = "GoBack"; + public static final String COMMAND_CLEAR_NAME = "Clear"; + public static final String SETTINGS_PROPERTY_BACKSTACK_ID = "backstackId"; + public static final String PROPERTY_BACK_TYPE = "backType"; + public static final String PROPERTY_BACK_VALUE = "backValue"; + + private static final List COMMANDS = new ArrayList<>(); + + //------------------------------------------------------------------------- + // Supported commands + //------------------------------------------------------------------------- + static { + COMMANDS.add(new ExtensionCommandDefinition(URI, COMMAND_GO_BACK_NAME) + .allowFastMode(true) + .property(PROPERTY_BACK_TYPE, BackType.COUNT.toString(), false) + .property(PROPERTY_BACK_VALUE, 1, false)); + COMMANDS.add(new ExtensionCommandDefinition(URI, COMMAND_CLEAR_NAME).allowFastMode(true)); + } + + @NonNull + private final BackStack mBackStack; + @NonNull + private final IBackCallback mBackCallback; + @NonNull + private final IOnAplFinishCallback mOnFinishCallback; + @Nullable + private BackStackDocument mBackstackDocument; + @Nullable + private IExtensionEventCallbackResult mResultCallback; + + private boolean mResponsibleForBackButton; + private String mCurrentDocumentId; + + /** + * Instantiate a new BackExtension. + * @param backStack the backstack to use + * @param callback the callback for handling GoBack commands + * @param onAplFinishCallback the callback for handling GoBack when the stack is empty + */ + public BackExtension(@NonNull BackStack backStack, @NonNull IBackCallback callback, + @NonNull IOnAplFinishCallback onAplFinishCallback) { + mBackStack = backStack; + mBackCallback = callback; + mOnFinishCallback = onAplFinishCallback; + } + + /** + * {@inheritDoc} + */ + @Override + @NonNull + public String getUri() { + return URI; + } + + /** + * {@inheritDoc} + */ + @Override + public Object getEnvironment() { + Map envObject = new HashMap<>(); + envObject.put("responsibleForBackButton", mResponsibleForBackButton); + envObject.put("backstack", mBackStack.getDocumentIds()); + Log.i(TAG, "getEnvironment"); + return envObject; + } + + /** + * {@inheritDoc} + */ + @Override + @NonNull + public List getCommandDefinitions() { + Log.i(TAG, "getCommandDefinitions"); + return COMMANDS; + } + + /** + * {@inheritDoc} + */ + @Override + @NonNull + public List getEventHandlers() { + Log.i(TAG, "getEventHandlers"); + return Collections.emptyList(); + } + + /** + * {@inheritDoc} + */ + @Override + @NonNull + public IExtensionEventCallback getCallback() { + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public void applySettings(Map settings) { + Object backStackId = settings.get(SETTINGS_PROPERTY_BACKSTACK_ID); + if (backStackId instanceof String) { + mCurrentDocumentId = (String) backStackId; + } + Log.i(TAG, "applySettings: " + mCurrentDocumentId); + } + + /** + * Returns the current document id. + * @return + */ + public String getDocumentId() { + return mCurrentDocumentId; + } + + /** + * Set the document id. + * @param id + */ + public void setDocumentId(String id) { + mCurrentDocumentId = id; + } + + /** + * {@inheritDoc} + */ + @Override + public void onExtensionEvent(String name, String uri, Map source, Map custom, + IExtensionEventCallbackResult resultCallback) { + mBackstackDocument = null; + mResultCallback = resultCallback; + Log.v(TAG, "onExtensionEvent: " + name + " source: " + source); + switch (name) { + case COMMAND_GO_BACK_NAME: + goBack(custom.get(PROPERTY_BACK_TYPE), custom.get(PROPERTY_BACK_VALUE)); + break; + case COMMAND_CLEAR_NAME: + eventHandled(true); + clear(); + break; + default: + eventHandled(false); + } + } + + /** + * Set the value of the Backstack environment property responsibleForBackButton. + * @param isResponsible true if the document needs to display the back button + */ + public void setResponsibleForBackButton(boolean isResponsible) { + mResponsibleForBackButton = isResponsible; + } + + /** + * Return the current back stack document. + * @return back stack document. + */ + public BackStackDocument getBackstackDocument() { + return mBackstackDocument; + } + + /** + * Add a document to the back stack. + * @param backStackDocument the document to be added to the back stack. + */ + public void addDocument(BackStackDocument backStackDocument) { + mBackStack.addDocument(backStackDocument); + } + + /** + * Go back using document id. + * @param documentId The id + */ + public void goBack(String documentId) { + if (TextUtils.isEmpty(documentId)) { + mBackstackDocument = mBackStack.popDocuments(0); + } else { + mBackstackDocument = mBackStack.popDocuments(documentId); + } + triggerGoBack(); + } + + /** + * Go back using index. + * @param index The index to go back on the stack. + */ + public void goBackIndex(int index) { + mBackstackDocument = mBackStack.popDocumentsAtIndex(index); + triggerGoBack(); + } + + /** + * Go back using count. + * @param count The number of elements that shoupd be popped off the stack. + */ + public void goBackCount(int count) { + mBackstackDocument = mBackStack.popDocuments(count); + triggerGoBack(); + } + + /** + * Clear the back stack. + */ + public void clear() { + mBackStack.clear(); + } + + /** + * Handle the go back command. + * @param objectBackType Back type: count, index, id + * @param backValue + */ + private void goBack(Object objectBackType, Object backValue) { + try { + int intBack = 0; + if (backValue instanceof Double) { + intBack = ((Double) backValue).intValue(); + } else if (backValue instanceof Integer) { + intBack = (Integer) backValue; + } + BackType backType = BackType.valueOf(objectBackType); + switch (backType) { + case ID: + goBack((String) backValue); + break; + case INDEX: + goBackIndex(intBack); + break; + case COUNT: + goBackCount(intBack); + break; + } + } catch (IllegalArgumentException | NullPointerException | ClassCastException e) { + Log.e(TAG, "Invalid keys in document. Doing nothing.", e); + } + } + + /** + * Notified callback of the document to go back to or finish if last element was popped off. + */ + private void triggerGoBack() { + eventHandled(true); + if (mBackstackDocument != null) { + mBackCallback.goBack(mBackstackDocument); + } else if (mBackStack.length() == 0) { + // Finish if we have no documents in the stack + mOnFinishCallback.onAplFinish(); + } + } + + /** + * Call back to signal if event was handled. + * @param handled + */ + private void eventHandled(boolean handled) { + if (mResultCallback != null) { + mResultCallback.onResult(handled); + } + mResultCallback = null; + } + + /** + * Supported back types. + */ + enum BackType { + COUNT, + INDEX, + ID; + + public static BackType valueOf(Object value) { + if (value instanceof BackType) { + return (BackType) value; + } + + String name = ((String) value).toUpperCase(); + return BackType.valueOf(name); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStack.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStack.java new file mode 100644 index 000000000..1195371b7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStack.java @@ -0,0 +1,169 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.extension.back; + +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * This object contains {@link BackStackDocument} objects and methods to support the apl Backstack. + * + * APL-Spec https://developer.amazon.com/en-US/docs/alexa/alexa-presentation-language/apl-ext-backstack.html + * + * Note: + * The top of the stack is {@link BackStack#length()} - 1. + */ +public class BackStack { + private static final String TAG = BackStack.class.getSimpleName(); + + private ArrayDeque mDocuments; + public BackStack() { + mDocuments = new ArrayDeque<>(); + } + + /** + * Adds a document to the BackStack. + * @param backStackDocument the document to add. + */ + void addDocument(@NonNull BackStackDocument backStackDocument) { + Log.v(TAG, "addDocument: " + backStackDocument.hashCode()); + mDocuments.addLast(backStackDocument); + } + + /** + * @return the length of the backstack. + */ + public int length() { + Log.v(TAG, "length: " + mDocuments.size()); + return mDocuments.size(); + } + + /** + * Clears the stack of documents. + */ + public void clear() { + Log.v(TAG, "clear: " + mDocuments.size()); + mDocuments.clear(); + } + + /** + * @return the list of document ids in the backstack. + */ + public List getDocumentIds() { + Log.v(TAG, "getDocumentIds: size: " + mDocuments.size()); + List documentIds = new ArrayList<>(); + for (BackStackDocument backStackDocument : mDocuments) { + documentIds.add(backStackDocument.getDocumentId()); + } + return documentIds; + } + + /** + * Gets the index of the most recent document with the id documentId. + * + * Note: documents are stored in ascending-recency order. That is, the order ['A','B','C'] means + * that 'C' is the most recent document. + * + * @param documentId the id to search for. + * @return the index of the most recent document in the stack matching documentId, + * or -1 if not found. + */ + int indexOf(@NonNull String documentId) { + int index = mDocuments.size() - 1; + for (Iterator itr = mDocuments.descendingIterator(); itr.hasNext();) { + if (documentId.equals(itr.next().getDocumentId())) { + return index; + } + index--; + } + + return -1; + } + + /** + * Removes all documents in the stack more recent than the most recent document with matching + * documentId and removes and returns that document. + * + * For example, if the stack is ['A','B','B','C'], then popDocuments('B') would return the document + * at index 2 and the stack would be ['A','B']. + * + * @param documentId the id of the document to return + * @return the most recent document in the stack whose document id matches the parameter. + */ + @Nullable + BackStackDocument popDocuments(@NonNull String documentId) { + Log.v(TAG, "popDocuments id: " + documentId); + int indexOfDocument = indexOf(documentId); + if (indexOfDocument == -1) { + return null; + } + return popDocumentsAtIndex(indexOfDocument); + } + + /** + * Removes all documents more recent than and including index and returns the document at index. + * + * For example, if the stack has ['A','B','C'], then both popDocumentsAtIndex(0) and + * popDocumentsAtIndex(-3) would return 'A' and the stack would be []. + * + * @param index the index of the document to return (can be negative to count backwards) + * @return the document at index. + */ + @Nullable + BackStackDocument popDocumentsAtIndex(int index) { + Log.v(TAG, "popDocuments index: " + index); + // Convert negative indexes to positive + if (index < 0) { + index = index + mDocuments.size(); + } + + if (index < 0 || index >= mDocuments.size()) { + return null; + } + + return popDocuments(mDocuments.size() - index); + } + + /** + * Removes count documents from the stack and returns the last one removed. + * + * For example, if the stack has documents ['A', 'B', 'C'], then popDocuments(2) would return 'B', + * and the stack would be: ['A']. + * + * @param count the number of documents to remove + * @return the count document in the stack + */ + @Nullable + BackStackDocument popDocuments(int count) { + Log.v(TAG, "popDocuments count: " + count + " size: " + mDocuments.size()); + if (count < 0 || count > mDocuments.size() || mDocuments.size() == 0) { + return null; + } + + for (int i = 0; i < count - 1; i++) { + mDocuments.removeLast(); + } + + return mDocuments.removeLast(); + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStackDocument.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStackDocument.java new file mode 100644 index 000000000..f9add018b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/BackStackDocument.java @@ -0,0 +1,119 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.extension.back; + +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.amazon.apl.android.DocumentState; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * Maintains a document with a specified ID in the backstack. + */ +public class BackStackDocument { + private static final String TAG = BackStackDocument.class.getSimpleName(); + + /** + * The document's backstack id. + */ + @NonNull + private final String mDocumentId; + + /** + * The document's cached state. + */ + @NonNull + private final DocumentState mDocumentState; + + /** + * Map of metadata that can be attached to this document. Metadata + * could be anything that the application can use to restore the + * document. + */ + @NonNull + private final Map mDocumentExtras = new HashMap<>(8); + + /** + * Creates a BackStack document to add to the backstack. + * @param documentId the backstackId + * @param documentState the document's cached state + */ + public BackStackDocument(@NonNull final String documentId, @NonNull final DocumentState documentState) { + mDocumentId = documentId; + mDocumentState = documentState; + } + + /** + * Return the document id. + * @return the document's backstack id. + */ + @NonNull + public String getDocumentId() { + return mDocumentId; + } + + /** + * Return the cached document. + * @return the document's cached state. + */ + @NonNull + public DocumentState getDocumentState() { + return mDocumentState; + } + + /** + * Return metadata associated with this document using a key. + * @param key the key + * @return An extra attached with this document. + */ + @SuppressWarnings("unchecked") + @NonNull + public T getExtra(@NonNull String key, @NonNull T fallbackValue) { + try { + return Objects.requireNonNull((T) mDocumentExtras.get(key)); + } catch (ClassCastException e) { + Log.w(TAG, "Type mismatch for key: " + key, e); + } catch (NullPointerException e) { + Log.i(TAG, "Key not found: " + key); + } + return fallbackValue; + } + + /** + * Check if a document extra exists. + * @param key the key + * @return true if the document extra was added. + */ + public boolean hasExtra(@NonNull String key) { + return mDocumentExtras.containsKey(key); + } + + /** + * Attach additional information with this document. + * @param key the key + * @param extra additional data + * @return this for chaining + */ + public BackStackDocument putExtra(@NonNull String key, @NonNull T extra) { + mDocumentExtras.put(key, extra); + return this; + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/IBackCallback.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/IBackCallback.java new file mode 100644 index 000000000..76ab64301 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/back/IBackCallback.java @@ -0,0 +1,26 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.extension.back; + +import androidx.annotation.NonNull; + +public interface IBackCallback { + /** + * Handle a successful GoBack command. + * @param backStackDocument the document to go back to. + */ + void goBack(@NonNull BackStackDocument backStackDocument); +} \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/localinfo/LocalInfoExtension.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/localinfo/LocalInfoExtension.java new file mode 100644 index 000000000..28c4dba62 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/extension/localinfo/LocalInfoExtension.java @@ -0,0 +1,209 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.extension.localinfo; + +import android.util.Log; + +import com.amazon.apl.android.APLController; +import com.amazon.apl.android.Event; +import com.amazon.apl.android.ExtensionCommandDefinition; +import com.amazon.apl.android.ExtensionEventHandler; +import com.amazon.apl.android.RootConfig; +import com.amazon.apl.android.dependencies.IExtensionEventCallback; +import com.amazon.apl.android.providers.IExtension; +import com.amazon.apl.android.render.interfaces.ILocalInfoDataConsumer; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * This class implements a built in APL extension used by the local info + * domain to expose data to the platform. This exposes a bidirectional communication + * channel for the platfom and APL runtime to communicate. + */ +public class LocalInfoExtension implements IExtensionEventCallback, IExtension { + public static final String TAG = LocalInfoExtension.class.getSimpleName(); + public static final String URI = "aplext:localinfo:10"; + public static final String COMMAND_SEND_POI_DATA_LIST = "SendPOIDataList"; + public static final String COMMAND_SELECT_POI = "SelectPOI"; + public static final String PROPERTY_DATA_LIST = "poiDataList"; + public static final String PROPERTY_POI_ID = "poiId"; + public static final String ON_SELECT_POI_EVENT_HANDLER = "OnSelectPOI"; + + private ILocalInfoDataConsumer mDataConsumer; + private RootConfig mRootConfig; + + //------------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------------- + + public LocalInfoExtension(RootConfig rootConfig) { + mRootConfig = rootConfig; + } + + //------------------------------------------------------------------------- + // Events and commands supported by the extension + //------------------------------------------------------------------------- + + private static final List COMMANDS = new ArrayList<>(); + private static final List EVENTS = new ArrayList<>(); + + static { + COMMANDS.add(new ExtensionCommandDefinition(URI, COMMAND_SEND_POI_DATA_LIST) + .allowFastMode(true) + .property(PROPERTY_DATA_LIST, null, true)); + COMMANDS.add(new ExtensionCommandDefinition(URI, COMMAND_SELECT_POI) + .allowFastMode(true) + .property(PROPERTY_POI_ID, "", false)); + EVENTS.add(new ExtensionEventHandler(URI, ON_SELECT_POI_EVENT_HANDLER)); + } + + //------------------------------------------------------------------------- + // IExtension + //------------------------------------------------------------------------- + + @Override + public List getCommandDefinitions() { + return COMMANDS; + } + + @Override + public List getEventHandlers() { + return EVENTS; + } + + @Override + public String getUri() { + return URI; + } + + @Override + public IExtensionEventCallback getCallback() { + return this; + } + + //------------------------------------------------------------------------- + // IExtensionEventCallback + //------------------------------------------------------------------------- + + @Override + public void onExtensionEvent(String name, String uri, Event event, Map source, + Map custom, IExtensionEventCallback.IExtensionEventCallbackResult resultCallback) { + handleOnExtensionEvent(name, uri, event, source, custom, resultCallback); + } + + @Override + public void onExtensionEvent(String name, String uri, Map source, Map custom, + IExtensionEventCallback.IExtensionEventCallbackResult resultCallback) { + handleOnExtensionEvent(name, uri, null, source, custom, resultCallback); + } + + private void handleOnExtensionEvent(String name, String uri, Event event, Map source, + Map custom, IExtensionEventCallback.IExtensionEventCallbackResult resultCallback) { + Log.v(TAG, "onExtensionEvent: " + uri + "/" + name + "/" + event + "/" + source + "/" + custom); + switch (name) { + case COMMAND_SEND_POI_DATA_LIST: + sendPOIDataListHandler(custom.get(PROPERTY_DATA_LIST)); + break; + case COMMAND_SELECT_POI: + selectPoiHandler(custom.get(PROPERTY_POI_ID)); + break; + } + } + + //------------------------------------------------------------------------- + // Public methods + //------------------------------------------------------------------------- + + /** + * The platform instance that will consume local info data from extension commands. + * + * @param consumer The consumer instance. + */ + public void setDataConsumer(ILocalInfoDataConsumer consumer) { + mDataConsumer = consumer; + } + + /** + * External selection of poi data item. + * @param controller The APL runtime instance. + * @param poiId Id of the selected data item. + */ + public void poiSelected(APLController controller, String poiId) { + Map map = new HashMap<>(); + map.put("poiId", poiId); + sendEventToDoc(controller, ON_SELECT_POI_EVENT_HANDLER, map); + } + + //------------------------------------------------------------------------- + // Private methods + //------------------------------------------------------------------------- + + /** + * Handle the SendPOIDataList command. + * @param objectDataList + */ + private void sendPOIDataListHandler(Object objectDataList) { + try { + JSONArray poiDataList = new JSONArray(); + Object[] data = (Object[]) objectDataList; + for (int i = 0; i < data.length; i++) { + HashMap poiItem = (HashMap) data[i]; + JSONObject poiJson = new JSONObject(poiItem); + Log.v(TAG, "data " + poiItem); + poiDataList.put(poiJson); + } + String dataJson = poiDataList.toString(); + if (mDataConsumer != null) { + mDataConsumer.aplDataAvailable(dataJson); + Log.v(TAG, "aplDataAvailable: " + dataJson); + } + } catch (IllegalArgumentException | NullPointerException | ClassCastException e) { + Log.w(TAG, "Invalid keys in document. Doing nothing.", e); + } + } + + /** + * Notify consumer that a data item was selected through the APL document. + * + * @param poiId The id of the data item selected. + */ + private void selectPoiHandler(Object poiId) { + String poiIdString = (String) poiId; + Log.v(TAG, "selectPoiHandler" + poiIdString); + if (mDataConsumer != null) { + mDataConsumer.aplDataItemSelectedById(poiIdString); + } + } + + /** + * Send an APL extension event to the APL document. + * @param controller current APL controller + * @param handler name of the extension event handler in the doc + * @param data map of data to send in the event + */ + private void sendEventToDoc(APLController controller, String handler, Map data) { + if (controller != null) { + Log.v(TAG, "extension sending event to " + handler); + controller.invokeExtensionEventHandler(URI, handler, data, false, null); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/font/AutoEmbeddedFontResolver.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/font/AutoEmbeddedFontResolver.java new file mode 100644 index 000000000..be78e6dee --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/font/AutoEmbeddedFontResolver.java @@ -0,0 +1,123 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.font; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Typeface; +import android.util.Log; + +import androidx.annotation.FontRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.content.res.ResourcesCompat; + +import com.amazon.apl.android.font.EmbeddedFontResolver; +import com.amazon.apl.android.font.FontKey; +import com.amazon.apl.android.render.R; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * This class provides support for Bookerly Amazon fonts. The fonts must be downloaded from the + * Amazon development portal. + */ +public class AutoEmbeddedFontResolver extends EmbeddedFontResolver { + private static final String TAG = AutoEmbeddedFontResolver.class.getSimpleName(); + private static final String BOOKERLY_FONT_FAMILY = "bookerly"; + + private final Context mAppContext; + + private static class ResFontKey { + @FontRes + final int fontRes; + final int weight; + + ResFontKey(final int weight, @FontRes final int fontRes) { + this.weight = weight; + this.fontRes = fontRes; + } + } + + // Mapping of font weights to font + private static final List sFontWeights = Collections.unmodifiableList( + Arrays.asList(new ResFontKey(100, R.font.bookerly_lcd_lt), new ResFontKey(300, R.font.bookerly_lcd_rg), + new ResFontKey(600, R.font.bookerly_lcd_rg), new ResFontKey(700, R.font.bookerly_lcd_bd))); + + public AutoEmbeddedFontResolver(@NonNull final Context context) { + super(context); + mAppContext = context; + } + + /** + * If Bookerly font is requested then this method will handle + * returning the correct typeface for that font family. Otherwise + * it delegates to the parent class. + * + * @param key The requested font key. + * @return The requested font, or null if not found. + */ + @NonNull + @Override + public Typeface findFont(@NonNull FontKey key) { + Typeface result = null; + + if (key.getFamily().equalsIgnoreCase(BOOKERLY_FONT_FAMILY)) { + try { + result = findAPLFont(key); + } catch (final Resources.NotFoundException ex) { + Log.e(TAG, "Exception finding embedded app font", ex); + } + } + + if (result == null) { + Log.d(TAG, "Looking for non bookerly font"); + result = super.findFont(key); + } + + return result; + } + + @Nullable + private Typeface findAPLFont(@NonNull final FontKey key) { + // Get the closest APLFont font + int minDiff = Integer.MAX_VALUE; + AutoEmbeddedFontResolver.ResFontKey bestKey = null; + List fontWeights = sFontWeights; + + for (final AutoEmbeddedFontResolver.ResFontKey currentKey : fontWeights) { + final int currentWeight = currentKey.weight; + + if (minDiff > Math.abs(currentWeight - key.getWeight())) { + minDiff = Math.abs(currentWeight - key.getWeight()); + bestKey = currentKey; + } + } + + if (bestKey != null) { + Log.i(TAG, "Best key: " + bestKey.weight + " requested: " + key.getWeight()); + final Typeface result = ResourcesCompat.getFont(mAppContext, bestKey.fontRes); + if (key.isItalic()) { + return Typeface.create(result, Typeface.ITALIC); + } + return result; + } + + return null; + } +} \ No newline at end of file diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java similarity index 87% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java index a6fb1184e..847ae8be8 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLContentListener.java @@ -71,4 +71,17 @@ public interface IAPLContentListener { * @param [in] token The APL presentation token associated with the current rendered document. */ public void onInterruptCommandSequence(String token); + + /** + * Notifies that APL runtime properties should be changed on the rendered document. + * @param properties JSON string containing one or more properties. + * @code{.json} + * { + * "drivingState" : "parked|moving", + * "theme" : "light|light-gray1|light-gray2|dark|dark-black|dark-gray", + * "video" : "enabled|disabled" + * } + * @endcode + */ + public void onAPLRuntimeProperties(String properties); } diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLEventSender.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLEventSender.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLEventSender.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLEventSender.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLOptionsBuilderProvider.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLOptionsBuilderProvider.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLOptionsBuilderProvider.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLOptionsBuilderProvider.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLTokenProvider.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLTokenProvider.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLTokenProvider.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IAPLTokenProvider.java diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IDismissible.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IDismissible.java new file mode 100644 index 000000000..1fee143b1 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IDismissible.java @@ -0,0 +1,26 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.interfaces; + +/** + * Interface for notifying application UI when to dismiss. + */ +public interface IDismissible { + /** + * Callback to be called for dismissing. + */ + void onDismiss(); +} \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataConsumer.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataConsumer.java new file mode 100644 index 000000000..2516fb3f3 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataConsumer.java @@ -0,0 +1,52 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.interfaces; + +/** + * This interface allows the platform to be notified when local info data + * is available or selected inside the APL document. + */ +public interface ILocalInfoDataConsumer { + /** + * Notifies the platform that the APL document contains local info data. + * + * @param data The list of data items containing + * @code{.json} + * [ + * { + * "id" : "", + * "name" : "", + * "coordinate" : { + * "latitude" : , + * "longitude : + * } + * } + * ] + * @endcode + * @li id The identifier for the POI data item. + * @li name The name associated with the POI data item. + * @li coordinate A JSON object containing the geocoordinates for the POI data item. + */ + void aplDataAvailable(String data); + + /** + * Notifies the platform that a POI data item was selected in the APL document. This + * allows the platform to highlight the selected data item. + * + * @param id The identifier for the selected POI data item. + */ + void aplDataItemSelectedById(String id); +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataReporter.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataReporter.java new file mode 100644 index 000000000..01e213b7f --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/ILocalInfoDataReporter.java @@ -0,0 +1,31 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.apl.android.render.interfaces; + +/** + * Interface used for allowing platform to report changes in local info + * that can affect the APL document. + */ +public interface ILocalInfoDataReporter { + /** + * Notifies the APL extension that a POI data item was selected by the platform. + * This allows the APL document to be updated to show details for the selected + * data item. + * + * @param id The identifier for the selected POI data item. + */ + void platformDataItemSelectedById(String id); +} diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java similarity index 76% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java index d4579a780..6615167fb 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/interfaces/IPresenter.java @@ -53,4 +53,22 @@ public interface IPresenter * @return */ IAPLEventSender getAplEventSender(); + + /** + * Saves a reference to the local info data consumer. + * + * @param consumer The object that consume local info data events. + */ + void setLocalInfoDataConsumer(ILocalInfoDataConsumer consumer); + + /** + * Callback to notify when APL window should be dismissed. + * @param dismissibleCallback + */ + void setDismissibleCallback(IDismissible dismissibleCallback); + + /** + * This should be called to stop execution when there is a barge in. + */ + void cancelExecution(); } diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java similarity index 98% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java index f8ef28efe..16dca29f2 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayer.java @@ -32,7 +32,7 @@ * content. */ public class APLMediaPlayer extends MediaPlayer implements AudioFocusController.PlaybackController { - private static final String TAG = "APLMediaPlayer"; + private static final String TAG = APLMediaPlayer.class.getSimpleName(); private final IAPLEventSender mAplEventSender; private final IAPLTokenProvider mAplTokenProvider; diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayerProvider.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayerProvider.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayerProvider.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/media/APLMediaPlayerProvider.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/NetworkExecutor.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/NetworkExecutor.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/NetworkExecutor.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/NetworkExecutor.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java similarity index 98% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java index 2672e1cfa..23f8e63a9 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/network/OkHttpClientWrapper.java @@ -35,7 +35,7 @@ * Wrapper around {@link OkHttpClient} to facilitate reading from cache first and refreshing later. */ public class OkHttpClientWrapper { - private static final String TAG = "OkHttpClientWrapper"; + private static final String TAG = OkHttpClientWrapper.class.getSimpleName(); public static final String CLOUDFRONT_LOCATION_PREFIX = "https://d2na8397m465mh.cloudfront.net/packages/"; diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java similarity index 95% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java index 735b9c51f..25f837d27 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/APLPayload.java @@ -29,7 +29,7 @@ @AllArgsConstructor @Getter public abstract class APLPayload { - private static final String TAG = "APLPayload"; + private static final String TAG = APLPayload.class.getSimpleName(); public static final String FIELD_PRESENTATION_TOKEN = "presentationToken"; diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/ExecuteCommandPayload.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/ExecuteCommandPayload.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/ExecuteCommandPayload.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/ExecuteCommandPayload.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java similarity index 97% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java index 3087c8699..88b44b9cb 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/PresentationSession.java @@ -39,7 +39,7 @@ @EqualsAndHashCode @Builder public class PresentationSession { - private static final String TAG = "PresentationSession"; + private static final String TAG = PresentationSession.class.getSimpleName(); public static final String FIELD_SKILL_ID = "skillId"; public static final String FIELD_ID = "id"; diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java similarity index 98% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java index c8780a96b..9e83afdb1 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderDocumentPayload.java @@ -59,7 +59,7 @@ */ @Getter public class RenderDocumentPayload extends APLPayload { - private static final String TAG = "RenderDocumentPayload"; + private static final String TAG = RenderDocumentPayload.class.getSimpleName(); private static final Map MODE_MAP = new HashMap() { { diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderedDocumentStatePayload.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderedDocumentStatePayload.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderedDocumentStatePayload.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/RenderedDocumentStatePayload.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/TimeoutType.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/TimeoutType.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/TimeoutType.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/TimeoutType.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/UserEventPayload.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/UserEventPayload.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/UserEventPayload.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/payload/UserEventPayload.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java similarity index 96% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java index 22ebf51fa..97e593ef1 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayer.java @@ -32,7 +32,7 @@ * and request Android audio focus. */ public class APLTtsPlayer extends TtsPlayer implements AudioFocusController.PlaybackController { - private static final String TAG = "APLTtsPlayer"; + private static final String TAG = APLTtsPlayer.class.getSimpleName(); private final IAPLEventSender mAplEventSender; private final IAPLTokenProvider mAplTokenProvider; @@ -60,7 +60,7 @@ public void onPlayerStateChanged(boolean playWhenReady, @NonNull AudioPlayer.Aud if (state == AudioPlayer.AudioPlayerState.STATE_PREPARING) { Log.v(TAG, "Acquire APL focus"); - } else if (state == AudioPlayer.AudioPlayerState.STATE_ENDED) { + } else if (state == AudioPlayer.AudioPlayerState.STATE_ENDED || state == AudioPlayer.AudioPlayerState.STATE_IDLE) { mAplEventSender.sendActivityEventRequest( mAplTokenProvider.getToken(), IAPLEventSender.ActivityEvent.DEACTIVATED); Log.v(TAG, "Release APL focus"); diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java similarity index 96% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java index d3f8c56d6..7ae10258c 100644 --- a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/tts/APLTtsPlayerProvider.java @@ -34,7 +34,7 @@ * Android view host to create a TTS player instance. */ public class APLTtsPlayerProvider implements ITtsPlayerProvider { - private static final String TAG = "APLTtsPlayerProvider"; + private static final String TAG = APLTtsPlayerProvider.class.getSimpleName(); private Context mContext; private APLTtsPlayer mTtsPlayer; diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/RenderDocumentUtils.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/RenderDocumentUtils.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/RenderDocumentUtils.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/RenderDocumentUtils.java diff --git a/platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/ViewportUtils.java b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/ViewportUtils.java similarity index 100% rename from platforms/android/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/ViewportUtils.java rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/java/com/amazon/apl/android/render/utils/ViewportUtils.java diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/libs/.gitignore b/aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/libs/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/libs/.gitignore rename to aacs/android/app-components/alexa-auto-apl-renderer/modules/apl-render/src/main/libs/.gitignore diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/proguard-rules.pro b/aacs/android/app-components/alexa-auto-apl-renderer/proguard-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-apl-renderer/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/AndroidManifest.xml new file mode 100644 index 000000000..e3a341ac3 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/AndroidManifest.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/assets/APLViewport.json b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/assets/APLViewport.json new file mode 100644 index 000000000..99c186ba6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/assets/APLViewport.json @@ -0,0 +1,113 @@ +{ + "_comment": "AACS config for APL visual characteristics.", + "aacs.alexa": { + "gui": { + "visualCharacteristics": [ + { + "type": "AlexaInterface", + "interface": "Alexa.InteractionMode", + "version": "1.1", + "configurations": { + "interactionModes": [ + { + "id": "{{STRING}}", + "uiMode": "AUTO", + "interactionDistance": { + "unit": [ "CENTIMETERS", "INCHES" ], + "value": "{INTEGER}" + }, + "touch": [ "SUPPORTED", "UNSUPPORTED" ], + "keyboard": [ "SUPPORTED", "UNSUPPORTED" ], + "video": [ "SUPPORTED", "UNSUPPORTED" ], + "dialog": [ "SUPPORTED", "UNSUPPORTED" ] + } + ] + } + }, + { + "type": "AlexaInterface", + "interface": "Alexa.Presentation.APL.Video", + "version": "1.0", + "configurations": { + "video": { + "codecs": [ + "H_264_42", + "H_264_41" + ] + } + } + }, + { + "type": "AlexaInterface", + "interface": "Alexa.Display.Window", + "version": "1.0", + "configurations": { + "templates": [ + { + "id": "{STRING}", + "type": "STANDARD", + "configuration": { + "sizes": [ + { + "type": "DISCRETE", + "id": "{STRING}", + "value": { + "unit": "PIXEL", + "value": { + "width": "{INTEGER}", + "height": "{INTEGER}" + } + } + } + ], + "interactionModes": [ + "{STRING}" + ] + } + } + ] + } + }, + { + "type": "AlexaInterface", + "interface": "Alexa.Display", + "version": "1.0", + "configurations": { + "display": { + "type": "PIXEL", + "touch": [ "SINGLE", "UNSUPPORTED" ], + "shape": [ "RECTANGLE", "ROUND" ], + "dimensions": { + "resolution": { + "unit": "PIXEL", + "value": { + "width": "{INTEGER}", + "height": "{INTEGER}" + } + }, + "physicalSize": { + "unit": [ "CENTIMETERS", "INCHES" ], + "value": { + "width": "{DECIMAL}", + "height": "{DECIMAL}" + } + }, + "pixelDensity": { + "unit": "DPI", + "value": "{INTEGER}" + }, + "densityIndependentResolution": { + "unit": "DP", + "value": { + "width": "{INTEGER}", + "height": "{INTEGER}" + } + } + } + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLDirective.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLDirective.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLDirective.java rename to aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLDirective.java diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLFragment.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLFragment.java new file mode 100644 index 000000000..73ea8c520 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLFragment.java @@ -0,0 +1,340 @@ +package com.amazon.alexa.auto.apl; + +import static com.amazon.aacsconstants.AASBConstants.AlexaClient.DIALOG_STATE_LISTENING; +import static com.amazon.alexa.auto.apl.Constants.STATE; +import static com.amazon.alexa.auto.apps.common.Constants.APL_RUNTIME_PROPERTIES; +import static com.amazon.alexa.auto.apps.common.Constants.APL_RUNTIME_PROPERTY_DRIVING_STATE_NAME; +import static com.amazon.alexa.auto.apps.common.Constants.APL_RUNTIME_PROPERTY_THEME_NAME; + +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.apis.app.AlexaApp; +import com.amazon.alexa.auto.apis.session.SessionActivityController; +import com.amazon.alexa.auto.apl.handler.APLHandler; +import com.amazon.alexa.auto.apps.common.util.FileUtil; +import com.amazon.alexa.auto.apps.common.util.Preconditions; +import com.amazon.apl.android.APLLayout; +import com.amazon.apl.android.render.APLPresenter; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.ref.WeakReference; + +/** + * Fragment for Alexa Auto APL screen. + */ +public class APLFragment extends Fragment { + private static final String TAG = APLFragment.class.getSimpleName(); + + private static final double APL_FRAGMENT_MARGIN_RATIO = 0.05; + + @Nullable + private APLHandler mAplHandler; + @NonNull + private final APLDirectiveReceiver mAPLReceiver; + + private JSONArray mVisualConfig; + private String mDefaultWindowId; + private int mAPLViewPortWidth; + private int mAPLViewPortHeight; + private Bundle mCreationArgs; + + private String mCurrentPayload = ""; + + private APLLayout mAPLLayout; + + public APLFragment() { + mAPLReceiver = new APLDirectiveReceiver(); + } + + @Override + public void onStart() { + Log.d(TAG, "onStart"); + super.onStart(); + EventBus.getDefault().register(mAPLReceiver); + } + + @Override + public void onStop() { + Log.d(TAG, "onStop"); + super.onStop(); + if (mAplHandler != null) { + mAplHandler.cancelExecution(); + } + EventBus.getDefault().unregister(mAPLReceiver); + } + + @Override + public void onDestroy() { + Log.d(TAG, "onDestroy"); + super.onDestroy(); + handleClearDocumentIntent(mCurrentPayload); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + Log.d(TAG, "onViewCreated"); + super.onViewCreated(view, savedInstanceState); + + Context context = getContext(); + Preconditions.checkNotNull(context); + + mCreationArgs = getArguments(); + if (mCreationArgs != null) { + View fragmentView = requireView(); + mAPLLayout = fragmentView.findViewById(R.id.apl); + + WeakReference contextWk = new WeakReference<>(context); + mAplHandler = new APLHandler(contextWk, new AACSMessageSender(contextWk, new AACSSender()), mAPLLayout); + } + + FileUtil.readAACSConfigurationAsync(context).subscribe(this::buildAPLPresenter); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + Context context = getContext(); + Preconditions.checkNotNull(context); + + //--------------------------------------------------------------------- + // Initialize the APL Runtime. This must be called during + // Activity.onCreate() or prior to APLLayout inflation. + //--------------------------------------------------------------------- + APLPresenter.initialize(context); + + // Inflate the layout for this fragment + return inflater.inflate(R.layout.fragment_apl, container, false); + } + + private void handleRenderDocumentIntent(@NonNull Bundle creationArgs) { + Preconditions.checkNotNull(mAplHandler); + + try { + String payload = creationArgs.getString(Constants.PAYLOAD); + Log.i(TAG, "handleRenderDocumentIntent payload: " + payload); + Preconditions.checkNotNull(payload); + + JSONObject json = new JSONObject(payload); + String token = json.getString(Constants.TOKEN); + String renderPayload = json.getString(Constants.PAYLOAD); + + mAplHandler.renderDocument(renderPayload, token, mDefaultWindowId); + } catch (Exception exception) { + Log.w(TAG, "Failed to handle render document. Error:" + exception); + } + } + + private void handleClearDocumentIntent(@NonNull String payload) { + if (mAplHandler != null) { + try { + JSONObject json = new JSONObject(payload); + String token = json.getString(Constants.TOKEN); + + mAplHandler.clearDocument(token); + } catch (Exception exception) { + Log.w(TAG, "Failed to handle clear document. Error:" + exception); + } + } + } + + private void handleExecuteCommandsIntent(@NonNull String payload) { + Preconditions.checkNotNull(mAplHandler); + try { + JSONObject json = new JSONObject(payload); + String token = json.getString(Constants.TOKEN); + String executeCommandPayload = json.getString(Constants.PAYLOAD); + + mAplHandler.executeCommands(executeCommandPayload, token); + } catch (Exception exception) { + Log.w(TAG, "Failed to handle execute commands. Error:" + exception); + } + } + + private void handleUpdateAPLRuntimePropertiesIntent(@NonNull String payload) { + Preconditions.checkNotNull(mAplHandler); + try { + // Construct APL runtime properties with local cached values. + String aplRuntimeProperties = constructAPLRuntimeProperties(); + mAplHandler.handleAPLRuntimeProperties(aplRuntimeProperties); + } catch (Exception exception) { + Log.w(TAG, "Failed to handle update APL runtime properties commands. Error:" + exception); + } + } + + private void handleDialogStateChangedIntent(@NonNull String payload) { + Preconditions.checkNotNull(mAplHandler); + try { + Log.v(TAG, "handleDialogStateChangedIntent: " + payload); + JSONObject dialogState = new JSONObject(payload); + // Cancel APL execution when we go into listening state + if (dialogState.getString(STATE).equals(DIALOG_STATE_LISTENING)) { + Log.v(TAG, "handleDialogStateChangedIntent: cancellingExecution"); + mAplHandler.cancelExecution(); + } + } catch (Exception exception) { + Log.w(TAG, "Failed to handle dialog state change. Error:" + exception); + } + } + + /** + * Initialize APLPresenter class to provide the orchestration logic in the APL rendering process. + * + * @param configs AACS configs. + */ + private void buildAPLPresenter(@NonNull String configs) { + Preconditions.checkNotNull(mAplHandler); + try { + JSONObject config = new JSONObject(configs); + mVisualConfig = + config.getJSONObject("aacs.alexa").getJSONObject("gui").getJSONArray("visualCharacteristics"); + + if (mVisualConfig.length() > 0) { + for (int i = 0; i < mVisualConfig.length(); i++) { + JSONObject currentElement = mVisualConfig.getJSONObject(i); + if ("Alexa.Display.Window".equals(currentElement.getString("interface"))) { + JSONArray templates = currentElement.getJSONObject("configurations").getJSONArray("templates"); + JSONObject template = templates.getJSONObject(0); + mDefaultWindowId = template.getString("id"); + mAPLViewPortWidth = template.getJSONObject("configuration") + .getJSONArray("sizes") + .getJSONObject(0) + .getJSONObject("value") + .getJSONObject("value") + .getInt("width"); + mAPLViewPortHeight = template.getJSONObject("configuration") + .getJSONArray("sizes") + .getJSONObject(0) + .getJSONObject("value") + .getJSONObject("value") + .getInt("height"); + } + } + } + + mAplHandler.buildAPLPresenter(mVisualConfig, mDefaultWindowId); + + setAPLFragmentLayout(mAPLLayout); + + mCurrentPayload = mCreationArgs.getString(Constants.PAYLOAD); + + String aplRuntimeProperties = constructAPLRuntimeProperties(); + if (!aplRuntimeProperties.isEmpty()) { + mAplHandler.handleAPLRuntimeProperties(aplRuntimeProperties); + } + + handleRenderDocumentIntent(mCreationArgs); + } catch (JSONException e) { + Log.w(TAG, "Failed to parse APL visual characteristics" + e); + } + } + + class APLDirectiveReceiver { + @Subscribe + public void OnReceive(APLDirective directive) { + mCurrentPayload = directive.message.payload; + switch (directive.message.action) { + case Action.AlexaClient.DIALOG_STATE_CHANGED: + Preconditions.checkNotNull(directive.message.payload); + handleDialogStateChangedIntent(directive.message.payload); + break; + case Action.APL.RENDER_DOCUMENT: + Preconditions.checkNotNull(directive.message.payload); + Bundle args = new Bundle(); + args.putString(Constants.PAYLOAD, directive.message.payload); + handleRenderDocumentIntent(args); + break; + case Action.APL.EXECUTE_COMMANDS: + Preconditions.checkNotNull(directive.message.payload); + handleExecuteCommandsIntent(directive.message.payload); + break; + case Action.APL.CLEAR_DOCUMENT: + handleClearDocumentIntent(directive.message.payload); + + Context context = getContext(); + Preconditions.checkNotNull(context); + + AlexaApp.from(context) + .getRootComponent() + .getComponent(SessionActivityController.class) + .ifPresent(SessionActivityController::removeFragment); + break; + case Action.APL.UPDATE_APL_RUNTIME_PROPERTIES: + Preconditions.checkNotNull(directive.message.payload); + handleUpdateAPLRuntimePropertiesIntent(directive.message.payload); + break; + default: + Log.d(TAG, "Unknown APL intent, action is " + directive.message.action); + break; + } + } + } + + /** + * Adjust APL fragment based on the APL Automotive viewport defined from the config, and set margins + * based on device's screen size. + * @param layout APL fragment layout + */ + private void setAPLFragmentLayout(APLLayout layout) { + requireActivity(); + + ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layout.getLayoutParams(); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int height = displayMetrics.heightPixels; + int width = displayMetrics.widthPixels; + + marginLayoutParams.width = mAPLViewPortWidth; + marginLayoutParams.height = mAPLViewPortHeight; + marginLayoutParams.topMargin = (int) (height * APL_FRAGMENT_MARGIN_RATIO); + marginLayoutParams.leftMargin = (int) (width * APL_FRAGMENT_MARGIN_RATIO); + + layout.setLayoutParams(marginLayoutParams); + } + + /** + * Construct APL runtime properties to render APL with updated properties value. + * Sample APL runtime properties format: {"drivingState":"parked","theme":"dark-gray"} + * @return APL runtime properties + */ + private String constructAPLRuntimeProperties() { + try { + JSONObject properties = new JSONObject(); + + SharedPreferences sharedPreferences = getContext().getSharedPreferences(APL_RUNTIME_PROPERTIES, 0); + Preconditions.checkNotNull(sharedPreferences); + String drivingStateValue = sharedPreferences.getString(APL_RUNTIME_PROPERTY_DRIVING_STATE_NAME, ""); + String themeValue = sharedPreferences.getString(APL_RUNTIME_PROPERTY_THEME_NAME, ""); + + if (!drivingStateValue.isEmpty()) { + properties.put(APL_RUNTIME_PROPERTY_DRIVING_STATE_NAME, drivingStateValue); + } + if (!themeValue.isEmpty()) { + properties.put(APL_RUNTIME_PROPERTY_THEME_NAME, themeValue); + } + + return properties.toString(); + } catch (JSONException e) { + Log.d(TAG, "Failed to construct APL runtime properties"); + return ""; + } + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLThemeDirective.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLThemeDirective.java new file mode 100644 index 000000000..00675894b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/APLThemeDirective.java @@ -0,0 +1,12 @@ +package com.amazon.alexa.auto.apl; + +import androidx.annotation.NonNull; + +public class APLThemeDirective { + @NonNull + public String themePayload; + + public APLThemeDirective(@NonNull String themePayload) { + this.themePayload = themePayload; + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/Constants.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/Constants.java new file mode 100644 index 000000000..f1a310a46 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/Constants.java @@ -0,0 +1,29 @@ +package com.amazon.alexa.auto.apl; + +public class Constants { + // AACS Intents + public static final String ID = "id"; + public static final String TOKEN = "token"; + public static final String PAYLOAD = "payload"; + public static final String NAME = "name"; + public static final String VALUE = "value"; + public static final String TYPE = "type"; + public static final String STATE = "state"; + public static final String RESULT = "result"; + public static final String ERROR = "error"; + public static final String SOURCE = "source"; + public static final String EVENT = "event"; + public static final String DOCUMENT = "document"; + public static final String VERSION = "version"; + public static final String PROPERTIES = "properties"; + public static final String COORDINATE = "coordinate"; + public static final String LONGITUDE = "longitude"; + public static final String LATITUDE = "latitude"; + + // APL Event States + public static final String APL_EVENT_STATE_ACTIVATED = "ACTIVATED"; + public static final String APL_EVENT_STATE_DEACTIVATED = "DEACTIVATED"; + public static final String APL_EVENT_STATE_ONE_TIME = "ONE_TIME"; + public static final String APL_EVENT_STATE_INTERRUPT = "INTERRUPT"; + public static final String APL_EVENT_STATE_UNKNOWN = "UNKNOWN"; +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/handler/APLHandler.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/handler/APLHandler.java new file mode 100644 index 000000000..644c8cdbc --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/handler/APLHandler.java @@ -0,0 +1,273 @@ +package com.amazon.alexa.auto.apl.handler; + +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.apl.Constants; +import com.amazon.apl.android.APLLayout; +import com.amazon.apl.android.render.APLPresenter; +import com.amazon.apl.android.render.interfaces.IAPLEventSender; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; + +import java.lang.ref.WeakReference; +import java.util.HashMap; + +/** + * This class provides the functionality to handle AACS APL events. + */ +public class APLHandler implements IAPLEventSender { + private static final String TAG = APLHandler.class.getSimpleName(); + + @NonNull + private final WeakReference mContextWk; + @NonNull + private AACSMessageSender mAACSSender; + + private APLLayout mAplLayout; + + private String mToken; + private String mVersion; + + @VisibleForTesting + APLPresenter mPresenter; + + public APLHandler(@NonNull WeakReference contextWk, @NonNull AACSMessageSender aacsSender, + @NonNull APLLayout aplLayout) { + mContextWk = contextWk; + mAACSSender = aacsSender; + mAplLayout = aplLayout; + } + + public void buildAPLPresenter(JSONArray visualCharacteristics, String defaultWindowId) { + HashMap aplLayouts = new HashMap(); + aplLayouts.put(defaultWindowId, mAplLayout); + + mPresenter = new APLPresenter(aplLayouts, visualCharacteristics, defaultWindowId, this); + } + + public void renderDocument(String jsonPayload, String token, String windowId) { + try { + // Extract document and data + JSONObject payload = new JSONObject(jsonPayload); + Log.i(TAG, "APL render document: " + payload.toString(4)); + JSONObject document = payload.getJSONObject(Constants.DOCUMENT); + + mToken = token; + mVersion = document.getString(Constants.VERSION); + } catch (JSONException e) { + Log.e(TAG, e.getMessage()); + } + + Log.i(TAG, "APL render document version: " + mVersion + " token: " + mToken + " windowId: " + windowId); + + mPresenter.onRenderDocument(jsonPayload, token, windowId); + } + + public void clearDocument(String token) { + Log.i(TAG, "clearDocument and visual context"); + mPresenter.onClearDocument(token); + } + + public void executeCommands(String payload, String token) { + Log.v(TAG, "executeCommands: token: " + token); + mToken = token; + + mPresenter.onExecuteCommands(payload, token); + } + + public void handleAPLRuntimeProperties(String aplRuntimeProperties) { + Log.v(TAG, "handleAPLRuntimeProperties: aplRuntimeProperties: " + aplRuntimeProperties); + mPresenter.onAPLRuntimeProperties(aplRuntimeProperties); + } + + public void interruptCommandSequence(String token) { + Log.v(TAG, "interruptCommandSequence: token: " + token); + mPresenter.onInterruptCommandSequence(token); + } + + private void processActivityEvent(String source, String event) { + try { + String payload = new JSONStringer() + .object() + .key(Constants.SOURCE) + .value(source) + .key(Constants.EVENT) + .value(event) + .endObject() + .toString(); + + mAACSSender.sendMessage(Topic.APL, Action.APL.PROCESS_ACTIVITY_EVENT, payload); + } catch (Exception exception) { + Log.e(TAG, "Failed to process activity event. Error: " + exception); + } + } + + private void renderDocumentResult(String token, boolean result, String error) { + sendResult(Action.APL.RENDER_DOCUMENT_RESULT, token, result, error); + } + + private void executeCommandsResult(String token, boolean result, String error) { + sendResult(Action.APL.EXECUTE_COMMANDS_RESULT, token, result, error); + } + + private void sendResult(String resultAction, String token, boolean result, String error) { + try { + String payload = new JSONStringer() + .object() + .key(Constants.TOKEN) + .value(token) + .key(Constants.RESULT) + .value(result) + .key(Constants.ERROR) + .value(error == null ? "" : error) + .endObject() + .toString(); + + mAACSSender.sendMessage(Topic.APL, resultAction, payload); + } catch (Exception exception) { + Log.e(TAG, "Failed to send result for " + resultAction + " Error: " + exception); + } + } + + private void sendUserEvent(String payload) { + try { + String msgPayload = + new JSONStringer().object().key(Constants.PAYLOAD).value(payload).endObject().toString(); + + mAACSSender.sendMessage(Topic.APL, Action.APL.SEND_USER_EVENT, msgPayload); + } catch (Exception exception) { + Log.e(TAG, "Failed to send user event. Error: " + exception); + } + } + + // IAPLEventSender implementation. + + @Override + public void sendWindowState(String state) { + Log.v(TAG, "sendWindowState: " + state); + try { + String msgPayload = new JSONStringer().object().key(Constants.STATE).value(state).endObject().toString(); + + mAACSSender.sendMessage(Topic.APL, Action.APL.SEND_DEVICE_WINDOW_STATE, msgPayload); + } catch (Exception exception) { + Log.e(TAG, "Failed to send device window state. Error: " + exception); + } + } + + @Override + public void sendClearCard() { + Log.v(TAG, "sendClearCard"); + mAACSSender.sendMessage(Topic.APL, Action.APL.CLEAR_CARD, null); + } + + @Override + public void sendClearAllExecuteCommands() { + Log.v(TAG, "sendClearAllExecuteCommands"); + mAACSSender.sendMessage(Topic.APL, Action.APL.CLEAR_ALL_EXECUTE_COMMANDS, null); + } + + @Override + public void sendUserEventRequest(String payload) { + Log.v(TAG, "sendUserEventRequest: payload: " + payload); + sendUserEvent(payload); + } + + @Override + public void sendDataSourceFetchEventRequest(String type, String payload) { + Log.v(TAG, "sendDataSourceFetchEventRequest: type: " + type + " payload: " + payload); + try { + String msgPayload = new JSONStringer() + .object() + .key(Constants.TYPE) + .value(type) + .key(Constants.PAYLOAD) + .value(payload) + .endObject() + .toString(); + + mAACSSender.sendMessage(Topic.APL, Action.APL.SEND_DATA_SOURCE_FETCH_REQUEST_EVENT, msgPayload); + } catch (Exception exception) { + Log.e(TAG, "Failed to send data source fetch request event. Error: " + exception); + } + } + + @Override + public void sendRuntimeErrorEventRequest(String payload) { + Log.v(TAG, "sendRuntimeErrorEvent: payload: " + payload); + try { + String msgPayload = + new JSONStringer().object().key(Constants.PAYLOAD).value(payload).endObject().toString(); + + mAACSSender.sendMessage(Topic.APL, Action.APL.SEND_RUNTIME_ERROR_EVENT, msgPayload); + } catch (Exception exception) { + Log.e(TAG, "Failed to send runtime error event. Error: " + exception); + } + } + + @Override + public void sendRenderDocumentResult(String token, boolean result, String error) { + Log.v(TAG, "sendRenderDocumentResult: token: " + token + " boolean: " + result + " error: " + error); + renderDocumentResult(token, result, error); + } + + @Override + public void sendExecuteCommandsResult(String token, boolean result, String error) { + Log.v(TAG, "sendExecuteCommandsResult: token: " + token + " result: " + result + " error: " + error); + executeCommandsResult(token, result, error); + } + + @Override + public void sendActivityEventRequest(String token, IAPLEventSender.ActivityEvent event) { + Log.v(TAG, "sendActivityEventRequest: token: " + token + " event: " + event); + processActivityEvent(token, translateActivityEvent(event)); + } + + @Override + public void sendContext(String state) { + Log.v(TAG, "sendContext: " + state); + try { + String msgPayload = new JSONStringer().object().key(Constants.STATE).value(state).endObject().toString(); + + mAACSSender.sendMessage(Topic.APL, Action.APL.SEND_DOCUMENT_STATE, msgPayload); + } catch (Exception exception) { + Log.e(TAG, "Failed to send user event. Error: " + exception); + } + } + + /** + * Cancel execution of APL commands. Should be called + * on a barge in. + */ + public void cancelExecution() { + if (mPresenter != null) { + mPresenter.cancelExecution(); + } + } + + private String translateActivityEvent(IAPLEventSender.ActivityEvent event) { + switch (event) { + case ACTIVATED: + return Constants.APL_EVENT_STATE_ACTIVATED; + case DEACTIVATED: + return Constants.APL_EVENT_STATE_DEACTIVATED; + case ONE_TIME: + return Constants.APL_EVENT_STATE_ONE_TIME; + case INTERRUPT: + return Constants.APL_EVENT_STATE_INTERRUPT; + case UNKNOWN: + return Constants.APL_EVENT_STATE_UNKNOWN; + } + + return Constants.APL_EVENT_STATE_UNKNOWN; + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLReceiver.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLReceiver.java new file mode 100644 index 000000000..e24b6d39a --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLReceiver.java @@ -0,0 +1,63 @@ +package com.amazon.alexa.auto.apl.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.fragment.app.Fragment; + +import com.amazon.aacsconstants.Action; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; +import com.amazon.alexa.auto.apis.app.AlexaApp; +import com.amazon.alexa.auto.apis.session.SessionActivityController; +import com.amazon.alexa.auto.apl.APLDirective; +import com.amazon.alexa.auto.apl.APLFragment; +import com.amazon.alexa.auto.apl.Constants; + +import org.greenrobot.eventbus.EventBus; + +public class APLReceiver extends BroadcastReceiver { + private static final String TAG = APLReceiver.class.getSimpleName(); + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null || intent.getAction() == null) { + return; + } + + AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { + Log.d(TAG, "APL msg.action " + message.action + " payload: " + message.payload); + if (Action.APL.RENDER_DOCUMENT.equals(message.action)) { + handleRenderDocument(context, message); + } else { + APLDirective directive = new APLDirective(message); + EventBus.getDefault().post(directive); + } + }); + } + + private void handleRenderDocument(@NonNull Context context, @NonNull final AACSMessage message) { + AlexaApp app = AlexaApp.from(context); + + app.getRootComponent().getComponent(SessionActivityController.class).ifPresent(sessionActivityController -> { + Fragment aplFragment; + Bundle args = new Bundle(); + args.putString(Constants.PAYLOAD, message.payload); + if (!sessionActivityController.isFragmentAdded()) { + aplFragment = new APLFragment(); + aplFragment.setArguments(args); + sessionActivityController.addFragment(aplFragment); + } else { + APLDirective directive = new APLDirective(message); + EventBus.getDefault().post(directive); + } + }); + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiver.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiver.java new file mode 100644 index 000000000..6799189e8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiver.java @@ -0,0 +1,144 @@ +package com.amazon.alexa.auto.apl.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.util.Log; + +import com.amazon.alexa.auto.apis.apl.APLTheme; +import com.amazon.alexa.auto.apl.Constants; +import com.amazon.alexa.auto.apps.common.util.Preconditions; + +import org.greenrobot.eventbus.EventBus; +import org.json.JSONException; +import org.json.JSONStringer; + +import androidx.annotation.VisibleForTesting; + +import static com.amazon.alexa.auto.apps.common.Constants.APL_RUNTIME_PROPERTIES; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_ID; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_NAME; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_VALUE_BLACK; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_VALUE_GRAY; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_VALUE_GRAY_ONE; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_VALUE_GRAY_TWO; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_DARK_THEME; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_LIGHT_THEME; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_MODE_VALUE_DARK; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_MODE_VALUE_LIGHT; + +/** + * Receiver for APL theme intent and send theme id to APL cloud. + * + * There are six APL themes available for automotive devices (uiMode-themeId): + * dark (default for dark or night mode) + * dark-black + * dark-gray + * light (default for light or day mode) + * light-gray1 + * light-gray2 + */ +public class APLThemeReceiver extends BroadcastReceiver { + private static final String TAG = APLThemeReceiver.class.getSimpleName(); + private static final String UI_MODE = "com.amazon.alexa.auto.uiMode"; + + @VisibleForTesting + String mPayload; + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceive: " + intent.getAction()); + + if (intent.getExtras() == null) { + Log.e(TAG, "APL theme intent's extra payload is null."); + return; + } + + String themeId = intent.getExtras().getString(THEME_ID); + Preconditions.checkNotNull(themeId); + + switch (getCurrentUiMode(context).toLowerCase()) { + case UI_MODE_VALUE_DARK: + if (themeId.equals(THEME_VALUE_BLACK) || themeId.equals(THEME_VALUE_GRAY) || themeId.isEmpty()) { + saveCurrentUiThemeBasedOnMode(context, UI_MODE_VALUE_DARK, themeId); + generateAPLThemePayload(themeId); + } else { + // If device is in dark mode, only black, gray and default themes are available + Log.e(TAG, "Invalid theme id is provided in dark mode."); + } + break; + case UI_MODE_VALUE_LIGHT: + if (themeId.equals(THEME_VALUE_GRAY_ONE) || themeId.equals(THEME_VALUE_GRAY_TWO) || themeId.isEmpty()) { + saveCurrentUiThemeBasedOnMode(context, UI_MODE_VALUE_LIGHT, themeId); + generateAPLThemePayload(themeId); + } else { + // If device is in dark mode, only gray1, gray2 and default themes are available + Log.e(TAG, "Invalid theme id is provided in light mode."); + } + break; + default: + Log.e(TAG, "Failed to get valid UI mode."); + mPayload = ""; + } + + APLTheme directive = new APLTheme(mPayload); + EventBus.getDefault().post(directive); + } + + private void saveCurrentUiThemeBasedOnMode(Context context, String uiMode, String theme) { + SharedPreferences.Editor editor; + if (uiMode.equals(UI_MODE_VALUE_DARK)) { + editor = context.getSharedPreferences(UI_DARK_THEME, 0).edit(); + } else { + editor = context.getSharedPreferences(UI_LIGHT_THEME, 0).edit(); + } + editor.putString(THEME_ID, theme); + editor.apply(); + + saveAPLThemeProperties(context, uiMode, theme); + } + + private String getCurrentUiMode(Context context) { + SharedPreferences sharedPreferences = context.getSharedPreferences(UI_MODE, 0); + if (sharedPreferences != null) { + return sharedPreferences.getString(UI_MODE, ""); + } else { + return ""; + } + } + + /** + * Saving APL theme properties for rendering APL template with the updated APL theme. + * @param context Android context + * @param uiMode day/night mode + * @param theme APL theme + */ + private void saveAPLThemeProperties(Context context, String uiMode, String theme) { + SharedPreferences.Editor editor = context.getSharedPreferences(APL_RUNTIME_PROPERTIES, 0).edit(); + if (theme.isEmpty()) { + editor.putString(THEME_NAME, uiMode); + } else { + editor.putString(THEME_NAME, uiMode + "-" + theme); + } + editor.apply(); + } + + @VisibleForTesting + String generateAPLThemePayload(String themeId) { + try { + mPayload = new JSONStringer() + .object() + .key(Constants.NAME) + .value(THEME_ID) + .key(Constants.VALUE) + .value(themeId) + .endObject() + .toString(); + } catch (JSONException e) { + Log.e(TAG,"Failed to parse APL theme payload."); + mPayload = ""; + } + return mPayload; + } +} diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/layout/fragment_apl.xml b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/layout/fragment_apl.xml new file mode 100644 index 000000000..42f1abca8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/layout/fragment_apl.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/values/dimens.xml new file mode 100644 index 000000000..b023083be --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 25dp + 25dp + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-apl-renderer/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/TestResourceFileReader.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/TestResourceFileReader.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/TestResourceFileReader.java rename to aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/TestResourceFileReader.java diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/handler/APLHandlerTest.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/handler/APLHandlerTest.java new file mode 100644 index 000000000..90d90bc77 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/handler/APLHandlerTest.java @@ -0,0 +1,67 @@ +package com.amazon.alexa.auto.apl.handler; + +import static org.mockito.Mockito.times; + +import android.content.Context; + +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.apl.android.APLLayout; +import com.amazon.apl.android.render.APLPresenter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.robolectric.RobolectricTestRunner; + +import java.lang.ref.WeakReference; + +@RunWith(RobolectricTestRunner.class) +public class APLHandlerTest { + private Context mContext; + private AACSMessageSender mAACSSender; + private APLLayout mAPLLayout; + private APLPresenter mAPLPresenter; + private APLLocalInfoHandler mAPLLocalInfoHandler; + + private APLHandler mClassUnderTest; + + @Before + public void setup() { + mContext = Mockito.mock(Context.class); + mAACSSender = Mockito.mock(AACSMessageSender.class); + mAPLLayout = Mockito.mock(APLLayout.class); + mAPLPresenter = Mockito.mock(APLPresenter.class); + mAPLLocalInfoHandler = Mockito.mock(APLLocalInfoHandler.class); + + mClassUnderTest = new APLHandler(new WeakReference<>(mContext), mAACSSender, mAPLLayout); + mClassUnderTest.mPresenter = mAPLPresenter; + mClassUnderTest.mAPLLocalInfoHandler = mAPLLocalInfoHandler; + } + + @Test + public void renderDocumentTest() { + mClassUnderTest.renderDocument("samplePayload", "sampleToken", "sampleWindowId"); + Mockito.verify(mClassUnderTest.mPresenter, times(1)) + .onRenderDocument("samplePayload", "sampleToken", "sampleWindowId"); + } + + @Test + public void clearDocumentTest() { + mClassUnderTest.clearDocument("sampleToken"); + Mockito.verify(mClassUnderTest.mPresenter, times(1)).onClearDocument("sampleToken"); + Mockito.verify(mClassUnderTest.mAPLLocalInfoHandler, times(1)).clearLocalInfoData(); + } + + @Test + public void executeCommandTest() { + mClassUnderTest.executeCommands("samplePayload", "sampleToken"); + Mockito.verify(mClassUnderTest.mPresenter, times(1)).onExecuteCommands("samplePayload", "sampleToken"); + } + + @Test + public void handleAPLRuntimePropertiesTest() { + mClassUnderTest.handleAPLRuntimeProperties("sampleAPLProperties"); + Mockito.verify(mClassUnderTest.mPresenter, times(1)).onAPLRuntimeProperties("sampleAPLProperties"); + } +} diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java similarity index 87% rename from platforms/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java rename to aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java index 530db2a3e..4e150c7b4 100644 --- a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLReceiverTest.java @@ -68,6 +68,15 @@ public void handleClearDocumentTest() { Assert.assertEquals(receiveMessageAction, Action.APL.CLEAR_DOCUMENT); } + @Test + public void handleUpdateAPLRuntimePropertiesTest() { + Intent getClearDocumentIntent = generateIntent("aacs/UpdateAPLRuntimeProperties.json", "com.amazon.aacs.aasb.UpdateAPLRuntimeProperties"); + mClassUnderTest.onReceive(mContext, getClearDocumentIntent); + Assert.assertEquals(receiveMessageTopic, Topic.APL); + Assert.assertEquals(receiveMessageAction, Action.APL.UPDATE_APL_RUNTIME_PROPERTIES); + } + + private Intent generateIntent(String resPath, String action) { Intent intent = new Intent(action); Optional sampleAACSAPLMessage = TestResourceFileReader.readFileContent(resPath); diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiverTest.java b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiverTest.java new file mode 100644 index 000000000..8e0bc36a6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/java/com/amazon/alexa/auto/apl/receiver/APLThemeReceiverTest.java @@ -0,0 +1,101 @@ +package com.amazon.alexa.auto.apl.receiver; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; + +import com.amazon.alexa.auto.apis.apl.APLTheme; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.spy; + +@RunWith(RobolectricTestRunner.class) +public class APLThemeReceiverTest { + @Mock + private Context mContext; + + private APLThemeReceiver mClassUnderTest; + private EventBus eventBus; + + private SharedPreferences mSharedPrefs; + private SharedPreferences.Editor mEditor; + + private String receiveThemePayload; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + mClassUnderTest = spy(new APLThemeReceiver()); + + mSharedPrefs = Mockito.mock(SharedPreferences.class); + mEditor = Mockito.mock(SharedPreferences.Editor.class); + Mockito.when(mContext.getSharedPreferences(anyString(), anyInt())).thenReturn(mSharedPrefs); + Mockito.when(mSharedPrefs.edit()).thenReturn(mEditor); + + EventBus.getDefault().register(this); + eventBus = spy(EventBus.getDefault()); + } + + @Test + public void handleValidAPLDarkThemeUpdateTest() { + String themeId = "gray"; + Mockito.when(mSharedPrefs.getString("com.amazon.alexa.auto.uiMode", "")).thenReturn("dark"); + Intent getAPLThemeUpdateIntent = + generateIntent(themeId); + mClassUnderTest.onReceive(mContext, getAPLThemeUpdateIntent); + Assert.assertNotNull(mClassUnderTest.mPayload); + Assert.assertEquals(receiveThemePayload, mClassUnderTest.generateAPLThemePayload(themeId)); + } + + @Test + public void handleInvalidAPLDarkThemeUpdateTest() { + Mockito.when(mSharedPrefs.getString("com.amazon.alexa.auto.uiMode", "")).thenReturn("dark"); + Intent getAPLThemeUpdateIntent = + generateIntent("gray1"); + mClassUnderTest.onReceive(mContext, getAPLThemeUpdateIntent); + Assert.assertNull(mClassUnderTest.mPayload); + } + + @Test + public void handleValidAPLLightThemeUpdateTest() { + String themeId = "gray1"; + Mockito.when(mSharedPrefs.getString("com.amazon.alexa.auto.uiMode", "")).thenReturn("light"); + Intent getAPLThemeUpdateIntent = + generateIntent(themeId); + mClassUnderTest.onReceive(mContext, getAPLThemeUpdateIntent); + Assert.assertNotNull(mClassUnderTest.mPayload); + Assert.assertEquals(receiveThemePayload, mClassUnderTest.generateAPLThemePayload(themeId)); + } + + @Test + public void handleInvalidAPLLightThemeUpdateTest() { + Mockito.when(mSharedPrefs.getString("com.amazon.alexa.auto.uiMode", "")).thenReturn("light"); + Intent getAPLThemeUpdateIntent = + generateIntent("black"); + mClassUnderTest.onReceive(mContext, getAPLThemeUpdateIntent); + Assert.assertNull(mClassUnderTest.mPayload); + } + + private Intent generateIntent(String themeId) { + Intent intent = new Intent("com.amazon.alexa.auto.apl.UpdateAPLTheme"); + intent.putExtra("themeId", themeId); + return intent; + } + + @Subscribe + public void testOnReceiveEvent(APLTheme theme) { + receiveThemePayload = theme.getThemePayload(); + } +} diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json similarity index 91% rename from platforms/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json rename to aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json index 0e345cbdc..367b639e4 100644 --- a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/ClearDocument.json @@ -6,7 +6,7 @@ "topic": "APL" }, "messageType": "Publish", - "version": "3.2" + "version": "3.3" }, "payload": { "payload": "" diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json similarity index 92% rename from platforms/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json rename to aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json index 19d1c2972..0073d905b 100644 --- a/platforms/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/RenderDocument.json @@ -6,7 +6,7 @@ "topic": "APL" }, "messageType": "Publish", - "version": "3.2" + "version": "3.3" }, "payload": { "payload": "{this is a sample payload for APL}" diff --git a/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/UpdateAPLRuntimeProperties.json b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/UpdateAPLRuntimeProperties.json new file mode 100644 index 000000000..40137d067 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apl-renderer/src/test/resources/aacs/UpdateAPLRuntimeProperties.json @@ -0,0 +1,14 @@ +{ + "header": { + "id": "7fd5e391-572b-47ef-bf4f-34792d283e63", + "messageDescription": { + "action": "UpdateAPLRuntimeProperties", + "topic": "APL" + }, + "messageType": "Publish", + "version": "3.3" + }, + "payload": { + "properties": "{This is the sample for APL runtime properties}" + } +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/.gitignore b/aacs/android/app-components/alexa-auto-apps-common-ui/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/.gitignore rename to aacs/android/app-components/alexa-auto-apps-common-ui/.gitignore diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/README.md b/aacs/android/app-components/alexa-auto-apps-common-ui/README.md similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/README.md rename to aacs/android/app-components/alexa-auto-apps-common-ui/README.md diff --git a/aacs/android/app-components/alexa-auto-apps-common-ui/build.gradle b/aacs/android/app-components/alexa-auto-apps-common-ui/build.gradle new file mode 100644 index 000000000..1a7e754e4 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-ui/build.gradle @@ -0,0 +1,66 @@ +apply plugin: 'com.android.library' +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + sourceSets { + main { + def restrictedAssets = new File(gradle.ext.aacsRoot, "restrictedAssets") + if (restrictedAssets.exists()) { + project.logger.lifecycle("Building alexa-auto-apps-common-ui using Alexa assets..") + res.srcDirs = ['src/main/res', restrictedAssets.getCanonicalPath()] + } else { + project.logger.lifecycle("Building alexa-auto-apps-common-ui using placeholders..") + res.srcDirs = ['src/main/res', 'src/main/res-placeholders'] + } + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-apps-common-ui" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(':alexa-auto-apps-common-util') + implementation deps.androidx_appcompat + implementation deps.androidx_constraint + implementation deps.eventbus + implementation deps.androidx_recycler_view + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.roboelectric +} diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/proguard-rules.pro b/aacs/android/app-components/alexa-auto-apps-common-ui/proguard-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-apps-common-ui/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/CirclePageIndicatorDecoration.java b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/CirclePageIndicatorDecoration.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/CirclePageIndicatorDecoration.java rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/CirclePageIndicatorDecoration.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/LoadingDialog.java b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/LoadingDialog.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/LoadingDialog.java rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/LoadingDialog.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialog.java b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialog.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialog.java rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialog.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/PopupDialogUtil.java b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/PopupDialogUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/PopupDialogUtil.java rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/PopupDialogUtil.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/ViewUtils.java b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/ViewUtils.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/ViewUtils.java rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/java/com/amazon/alexa/auto/app/common/util/ViewUtils.java diff --git a/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res-placeholders/drawable/alexa_bubble_small.png b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res-placeholders/drawable/alexa_bubble_small.png new file mode 100755 index 0000000000000000000000000000000000000000..90d47828171e236a118b0f5d6cb4f11640f241d5 GIT binary patch literal 1424 zcmeAS@N?(olHy`uVBq!ia0vp^+CVJH!3HE(yuY3Xq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3)EF2VS{N990fib~Fff!FFfhDIU|_JC!N4G1FlSew4N!u!z$3Dlfq`2Xgc%uT z&5>YWV2sQRi71Ki^|4CM&(%vz$xlkvtH>8?tx|+mh4pF`@A3=GT*JzX3_A~@epi_YjT zlsNwXzwC{$8Hb(n(#+bAW_5ZLZC|}mC!6m(-_fPc+B*w$CI)4dXYEi3oYX6(cceE! z*{AKqOo>@%{)o&JRW z$6sfb>xG51{FRGqT5@mJS<|&?(F>)6&L*YT82k%49JYShrM{^58~0Cm{@da>?-u(7 zT-7pbm`$U&ckj%IeX&o)TYRGDR&MQuEKv&u|407`-mrS%+(O|fcXj?yX8Q*wk88dN zMX*eMs60pgzm`?3$G5i`hpw%9>d5S&Wh?!=e`+YteQ`+23} z)BKGe^`!H+e^mdHy?JR^q|Gf$nR^)&U$*Bb_s48jd8dUxuO)ex z-P)lf#b$od*zxJp5Zg?WTOvEO+jL>qV0Sw|BbqKV4%M z>o;jy{GJA(3z3t4+?*!+fbBZNyuf ztfXI0^6)#9^EsBsc23|Iw;K${6E`2_Pxk&Jse94jg1Rs7>msj`cdHjhGC$dNH2CbV zS97;E^tIRZ{%Kzj7V6P_G&~`Dsr5ni%dbqD`lg&t=Xshny=0-^%D5(5_L9bRwRIIj@R$FV_P6Q|IF$quMf+w?NFbkW`6em?r9t2?}emBIi9j+IIRBI?Duo+ zHAegG!~gRyKl;16WX-qruYOfOE6Ax}{r8mX57PlvLnlE!$E%=n&(qb literal 0 HcmV?d00001 diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/alexa_placeholder_logo.png b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res-placeholders/drawable/alexa_logo.png old mode 100644 new mode 100755 similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/alexa_placeholder_logo.png rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res-placeholders/drawable/alexa_logo.png diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/color/radio_button_color_selector.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/color/radio_button_color_selector.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/color/radio_button_color_selector.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/color/radio_button_color_selector.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/ic_close.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/ic_close.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/ic_close.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/ic_close.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/light_button_background.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/light_button_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/light_button_background.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/light_button_background.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/medium_component_background.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/medium_component_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/medium_component_background.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/medium_component_background.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/selected_rect_button_background.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/selected_rect_button_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/selected_rect_button_background.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/selected_rect_button_background.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/small_component_background.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/small_component_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/small_component_background.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/small_component_background.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_button_background.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_button_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_button_background.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_button_background.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_rect_button_background.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_rect_button_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_rect_button_background.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/drawable/transparent_rect_button_background.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/loading_dialog_layout.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/loading_dialog_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/loading_dialog_layout.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/loading_dialog_layout.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/simple_dialog_layout.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/simple_dialog_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/simple_dialog_layout.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/simple_dialog_layout.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/two_choice_dialog_layout.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/two_choice_dialog_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/two_choice_dialog_layout.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/layout/two_choice_dialog_layout.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/attrs.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/attrs.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/attrs.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/attrs.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/colors.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/colors.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/colors.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/colors.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/dimens.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/dimens.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.app.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.app.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.app.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.app.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/styles.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/theme-alexa-standard.xml b/aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/theme-alexa-standard.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/theme-alexa-standard.xml rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/main/res/values/theme-alexa-standard.xml diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/src/test/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialogTest.java b/aacs/android/app-components/alexa-auto-apps-common-ui/src/test/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialogTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/src/test/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialogTest.java rename to aacs/android/app-components/alexa-auto-apps-common-ui/src/test/java/com/amazon/alexa/auto/app/common/ui/TwoChoiceDialogTest.java diff --git a/extensions/bluetooth/samples/android/modules/sample-bluetooth/.gitignore b/aacs/android/app-components/alexa-auto-apps-common-util/.gitignore similarity index 100% rename from extensions/bluetooth/samples/android/modules/sample-bluetooth/.gitignore rename to aacs/android/app-components/alexa-auto-apps-common-util/.gitignore diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/README.md b/aacs/android/app-components/alexa-auto-apps-common-util/README.md new file mode 100644 index 000000000..f6b148513 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/README.md @@ -0,0 +1,10 @@ +# Alexa Auto Apps Common Util + +This package provides the AACS Sample App and app components with various helper classes to simplify the implementation. The provided utilities include: +* Start, Stop and share files with AACS. +* Get and set the Alexa properties. +* Handle the file operations. +* Get the enabled Alexa Auto SDK extra modules. +* Get the network connectivity status. +* Check the preconditions. +* Manage the ambient light sensor and Alexa Auto theme update. \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/build.gradle b/aacs/android/app-components/alexa-auto-apps-common-util/build.gradle new file mode 100644 index 000000000..f76a791b4 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/build.gradle @@ -0,0 +1,67 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 25 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-apps-common-util" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':aacscommonutils') + implementation project(':alexa-auto-apis') + + implementation deps.androidx_annotation + implementation deps.androidx_core + + // RX + implementation deps.rxjava3 + + // Eventbus + implementation deps.eventbus + + //Unit Tests + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.androidx_test_core + testImplementation deps.roboelectric +} diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/proguard-rules.pro b/aacs/android/app-components/alexa-auto-apps-common-util/proguard-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-apps-common-util/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/AndroidManifest.xml new file mode 100644 index 000000000..395650b02 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/Constants.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/Constants.java new file mode 100644 index 000000000..193a481b2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/Constants.java @@ -0,0 +1,44 @@ +package com.amazon.alexa.auto.apps.common; + +public class Constants { + // Voice Assistance Constants + public static final String ALEXA = "ALEXA"; + public static final String NONALEXA = "NONALEXA"; + public static final String ALEXA_AND_PTT = "ALEXA_AND_PTT"; + public static final String NONALEXA_AND_PTT = "NONALEXA_AND_PTT"; + public static final String VOICE_ASSISTANCE = "VOICE_ASSISTANCE"; + public static final String ALEXA_LOG_IN = "ALEXA_LOG_IN"; + public static final String SETUP_DONE = "SETUP_DONE"; + public static final String PUSH_TO_TALK = "PUSH_TO_TALK"; + public static final String CBL_START = "CBL_START"; + + public static final String UPDATE_ASSISTANT_STATUS = "UPDATE_ASSISTANT_STATUS"; + public static final String UPDATE_ASSISTANT_GESTURE = "UPDATE_ASSISTANT_GESTURE"; + public static final String ENABLE_ASSISTANT_AND_ASSIGN_TAP = "ENABLE_ASSISTANT_AND_ASSIGN_TAP"; + public static final String ASSISTANTS_STATE_CHANGED = "ASSISTANTS_STATE_CHANGED"; + public static final String ASSISTANTS_GESTURE_CHANGED = "ASSISTANTS_GESTURE_CHANGED"; + public static final String ENABLE = "ENABLE"; + public static final String DISABLE = "DISABLE"; + + // Assistant State + public static final String ALEXA_DISABLED = "ALEXA_DISABLED"; + public static final String NON_ALEXA_DISABLED = "NON_ALEXA_DISABLED"; + public static final String BOTH_DISABLED = "BOTH_DISABLED"; + public static final String BOTH_ENABLED = "BOTH_ENABLED"; + + // Amazonlite + public static final String MODELS = "models"; + public static final String PATH = "path"; + + // File provider + public static final String AACS_SAMPLE_APP_FILE_PROVIDER = "com.amazon.alexa.auto.app.fileprovider"; + + // APL Runtime Properties + public static final String APL_RUNTIME_PROPERTIES = "com.amazon.alexa.auto.apl.runtime.properties"; + public static final String APL_RUNTIME_PROPERTY_NAME_KEY = "name"; + public static final String APL_RUNTIME_PROPERTY_VALUE_KEY = "value"; + public static final String APL_RUNTIME_PROPERTY_DRIVING_STATE_NAME = "drivingState"; + public static final String APL_RUNTIME_PROPERTY_THEME_NAME = "theme"; + public static final String APL_RUNTIME_PROPERTY_DRIVING_STATE_VALUE_MOVING = "moving"; + public static final String APL_RUNTIME_PROPERTY_DRIVING_STATE_VALUE_PARKED = "parked"; +} diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java similarity index 95% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java index fda7042c6..8543b84a5 100644 --- a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceController.java @@ -58,6 +58,7 @@ public static void shareFilePermissionsOfSameType(@NonNull Context context, File parent, String[] filenames, String module) { + Log.i(TAG, "shareFilePermissionsOfSameType"); ArrayList fileUris = new ArrayList<>(); for (String name : filenames) { File file = new File(parent, name); @@ -82,7 +83,7 @@ public static void shareFilePermissionsOfSameType(@NonNull Context context, checkAndroidVersionAndStartService(context, shareFileIntent); } - private static void checkAndroidVersionAndStartService(@NonNull Context context, Intent intent) { + public static void checkAndroidVersionAndStartService(@NonNull Context context, Intent intent) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { context.startForegroundService(intent); } else { diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/message/AssistantMessage.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/message/AssistantMessage.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/message/AssistantMessage.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/message/AssistantMessage.java diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/DNDSettingsProvider.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/DNDSettingsProvider.java new file mode 100644 index 000000000..87dbe6d43 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/DNDSettingsProvider.java @@ -0,0 +1,69 @@ +package com.amazon.alexa.auto.apps.common.util; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONException; +import org.json.JSONStringer; + +import java.lang.ref.WeakReference; + +/** + * Service class for interacting with Alexa Do Not Disturb Settings + */ +public class DNDSettingsProvider { + private static final String TAG = DNDSettingsProvider.class.getCanonicalName(); + + public static final String DND_SETTINGS = "dnd-settings"; + public static final String DND_SETTING_ENABLED = "dnd-setting-enabled"; + public static final String DO_NOT_DISTURB_JSON_KEY = "doNotDisturb"; + public static final boolean DEFAULT_DND_PREFERENCE = false; + + + public static boolean updateDNDSetting(@NonNull Context context, boolean value) { + try { + updateDNDSettingInAACS(context, value); + updateDNDInPreferences(context, value); + return true; + } catch (JSONException e) { + Log.e(TAG, "Failed to update DND setting to:" + value); + return false; + } + } + + public static void updateDNDInPreferences(@NotNull Context context, boolean value) { + SharedPreferences.Editor editor = context.getSharedPreferences(DND_SETTINGS, 0).edit(); + editor.putBoolean(DND_SETTING_ENABLED, value); + editor.commit(); + } + + public static boolean isDNDSettingEnabled(@NonNull Context context) { + SharedPreferences sharedPreferences = context.getSharedPreferences(DND_SETTINGS, 0); + return sharedPreferences.getBoolean(DND_SETTING_ENABLED, DEFAULT_DND_PREFERENCE); + } + + public static void resetDNDSetting(@NonNull Context context) { + updateDNDSetting(context, DEFAULT_DND_PREFERENCE); + } + + private static void updateDNDSettingInAACS(@NotNull Context context, boolean value) throws JSONException { + String payload = new JSONStringer() + .object() + .key(DO_NOT_DISTURB_JSON_KEY) + .value(value) + .endObject() + .toString(); + new AACSMessageSender( + new WeakReference<>(context), new AACSSender()) + .sendMessage(Topic.DO_NOT_DISTURB, Action.DoNotDisturb.DO_NOT_DISTURB_CHANGED, payload); + } +} diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/EarconSoundSettingsProvider.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/EarconSoundSettingsProvider.java new file mode 100644 index 000000000..9a2520674 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/EarconSoundSettingsProvider.java @@ -0,0 +1,46 @@ +package com.amazon.alexa.auto.apps.common.util; + +import android.content.Context; +import android.content.SharedPreferences; + +import androidx.annotation.NonNull; + +/** + * Service class for interacting with Alexa Earcon Settings + */ +public class EarconSoundSettingsProvider { + private static final String TAG = EarconSoundSettingsProvider.class.getCanonicalName(); + + public static final String EARCON_SETTINGS = "earcon-settings"; + public static final String EARCON_SETTINGS_START = "earcon-settings-start"; + public static final String EARCON_SETTINGS_END = "earcon-settings-end"; + public static final boolean DEFAULT_SOUND_PREFERENCE = true; + + + public static void setStartEarconSetting(@NonNull Context context, boolean value) { + SharedPreferences.Editor editor = context.getSharedPreferences(EARCON_SETTINGS, 0).edit(); + editor.putBoolean(EARCON_SETTINGS_START, value); + editor.commit(); + } + + public static boolean isStartEarconSettingEnabled(@NonNull Context context) { + SharedPreferences sharedPreferences = context.getSharedPreferences(EARCON_SETTINGS, 0); + return sharedPreferences.getBoolean(EARCON_SETTINGS_START, DEFAULT_SOUND_PREFERENCE); + } + + public static void setEndEarconSetting(@NonNull Context context, boolean value) { + SharedPreferences.Editor editor = context.getSharedPreferences(EARCON_SETTINGS, 0).edit(); + editor.putBoolean(EARCON_SETTINGS_END, value); + editor.commit(); + } + + public static boolean isEndEarconSettingEnabled(@NonNull Context context) { + SharedPreferences sharedPreferences = context.getSharedPreferences(EARCON_SETTINGS, 0); + return sharedPreferences.getBoolean(EARCON_SETTINGS_END, DEFAULT_SOUND_PREFERENCE); + } + + public static void resetEarconSettings(@NonNull Context context) { + setStartEarconSetting(context, DEFAULT_SOUND_PREFERENCE); + setEndEarconSetting(context, DEFAULT_SOUND_PREFERENCE); + } +} diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/FileUtil.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/FileUtil.java new file mode 100644 index 000000000..5248f50a2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/FileUtil.java @@ -0,0 +1,219 @@ +package com.amazon.alexa.auto.apps.common.util; + +import android.content.Context; +import android.content.res.AssetManager; +import android.os.Environment; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; + +import io.reactivex.rxjava3.core.Single; + +import static com.amazon.alexa.auto.apps.common.Constants.MODELS; + +/** + * Alexa auto app file util class. + */ +public class FileUtil { + private static final String TAG = FileUtil.class.getSimpleName(); + + private static final String CONFIG_DIR = "config"; + private static final String AACS_CONFIG_FILE = "aacs_config.json"; + private static final String LOCALES_FILE = "locales.json"; + + /** + * Read content of configuration file asynchronously + * + * @param context Android Context. + * @return {@link Single} of {@link String} that is resolved when file + * contents are available. + */ + public static Single readAACSConfigurationAsync(@NonNull Context context) { + return readAACSConfigurationAsync(context, new Handler(Looper.getMainLooper())); + } + + /** + * Read content of configuration file asynchronously + * + * @param context Android Context. + * @param resultHandler Handler thread where result would be dispatched. + * @return {@link Single} of {@link String} that is resolved when file + * contents are available. + */ + public static Single readAACSConfigurationAsync(@NonNull Context context, @NonNull Handler resultHandler) { + return readAACSConfigurationAsync( + context, resultHandler, Environment.getExternalStorageDirectory().getAbsolutePath()); + } + + /** + * Read content of configuration file asynchronously + * + * @param context Android Context. + * @param resultHandler Handler thread where result would be dispatched. + * @param externalStorageDir Path to external storage directory. + * @return {@link Single} of {@link String} that is resolved when file + * contents are available. + */ + public static Single readAACSConfigurationAsync( + @NonNull Context context, @NonNull Handler resultHandler, @NonNull String externalStorageDir) { + return Single.create(emitter -> { + Thread readThread = new Thread(() -> { + try { + Preconditions.checkNotNull(context); + + String config = FileUtil.readAACSConfiguration(context, externalStorageDir); + + resultHandler.post(() -> emitter.onSuccess(config)); + } catch (IOException e) { + Log.e(TAG, "Failed to read AACS configuration. Error: " + e); + emitter.onError(e); + } + }); + + readThread.setDaemon(true); + readThread.start(); + }); + } + + /** + * Reads the content of Alexa locales file. + * + * @param context Android Context. + * @return File contents + */ + @NonNull + public static String readLocales(@NonNull Context context) { + AssetManager assetManager = context.getAssets(); + try { + return readStream(assetManager.open(LOCALES_FILE)); + } catch (IOException e) { + Log.e(TAG, "Failed to fetch locales from locales asset file."); + return ""; + } + } + + /** + * Copy wake word models to files directory + * @param context Android context. + */ + public static void copyModelsToFilesDir(Context context) { + Log.i(TAG, "copyModelsToFilesDir"); + File modelsDir = new File(context.getFilesDir(), MODELS); + if (!modelsDir.exists()) { + if (!modelsDir.mkdir()) { + Log.e(TAG, "Error creating models directory."); + return; + } + try { + AssetManager assetManager = context.getAssets(); + String[] modelAssets = assetManager.list(MODELS); + if (modelAssets != null) { + for (String next : modelAssets) { + if (copyFileFromAssetPath(MODELS + "/" + next, new File(modelsDir, next), false, assetManager)) + continue; + return; + } + } + } catch (IOException e) { + Log.e(TAG, String.format("Error while copying models from assets into filesDir. Error: %s", e.getMessage())); + } + } else { + Log.i(TAG, "Models directory already exists"); + } + } + + /** + * Copy file to destination path + * @param assetPath The file path to the asset. + * @param destFile The destination file. + * @param force True if coping even if the file already exists. False otherwise. + * @param assetManager The Android Asset Manager. + * @return True if the operation succeeds. False otherwise. + */ + private static boolean copyFileFromAssetPath( + String assetPath, File destFile, boolean force, AssetManager assetManager) { + if (!destFile.exists() || force) { + if (destFile.getParentFile().exists() || destFile.getParentFile().mkdirs()) { + // Copy the asset to the dest path + try (InputStream is = assetManager.open(assetPath); OutputStream os = new FileOutputStream(destFile)) { + byte[] buf = new byte[1024]; + int len; + while ((len = is.read(buf)) > 0) { + os.write(buf, 0, len); + } + } catch (IOException e) { + Log.e(TAG, "Could not copy file " + assetPath); + return false; + } + } else { + Log.e(TAG, "Could not create directory: " + destFile.getParentFile()); + return false; + } + } else { + Log.w(TAG, String.format("Skipping existing file in : %s to: %s", assetPath, destFile)); + } + return true; + } + + /** + * Reads the content of AACS configuration file. We will firstly read the config + * file from external storage, if the config file is not found, we will read the + * config from default file in assets. + * + * @param context Android Context. + * @return File contents + */ + @NonNull + private static String readAACSConfiguration(@NonNull Context context, @NonNull String externalStorageDir) + throws IOException { + String configFilePath = ""; + if (BuildConfig.DEBUG && android.os.Build.VERSION.SDK_INT >= 30) { + // Check if current build is Debug build and runtime Android API level is 30 or above so the application + // can read aacs_config.json from the scoped storage location + Log.d(TAG, "Reading from scoped storage"); + configFilePath = context.getExternalFilesDir(null) + "/" + AACS_CONFIG_FILE; + } else if (BuildConfig.DEBUG) { + // Check if current build is Debug build and installed at runtime Android API level below 30 + // so that AACS Sample Application can still maintain the legacy storage for aacs_config.json from /sdcard/ + Log.d(TAG, "Reading from legacy storage"); + configFilePath = externalStorageDir + "/" + AACS_CONFIG_FILE; + } + + try { + File fullPath = new File(configFilePath); + Log.d(TAG, + String.format("Reading %s from external storage.", configFilePath)); + return readStream(new FileInputStream(fullPath)); + } catch (Exception e) { + Log.w(TAG, + String.format("Cannot read %s from external storage. Error: %s", AACS_CONFIG_FILE, e.getMessage())); + } + + // Fallback to use built-in AACS Configuration + Log.d(TAG, "Fallback to use built-in AACS configuration"); + AssetManager assetManager = context.getAssets(); + return readStream(assetManager.open(CONFIG_DIR + "/" + AACS_CONFIG_FILE)); + } + + /** + * Read the content of stream as text string. + * + * @param inputStream Input stream. + * @return Content of input stream as text string. + */ + private static String readStream(@NonNull InputStream inputStream) throws IOException { + byte[] buffer = new byte[inputStream.available()]; + inputStream.read(buffer); + return new String(buffer, StandardCharsets.UTF_8); + } +} diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/LocaleUtil.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/LocaleUtil.java new file mode 100644 index 000000000..a8dfcf5d2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/LocaleUtil.java @@ -0,0 +1,44 @@ +package com.amazon.alexa.auto.apps.common.util; + +import java.util.HashMap; +import java.util.Locale; + +/** + * Class for Locale related utilities + */ +public class LocaleUtil { + + public static final String DEFAULT_DOMAIN = "amazon.com"; + private static HashMap localeAmazonDomainMap; + + public static void init() { + if (localeAmazonDomainMap == null) { + localeAmazonDomainMap = new HashMap<>(); + localeAmazonDomainMap.put("en_US", DEFAULT_DOMAIN); + localeAmazonDomainMap.put("en_GB", "amazon.co.uk"); + localeAmazonDomainMap.put("en_AU", "amazon.co.uk"); + localeAmazonDomainMap.put("en_CA", "amazon.co.uk"); + localeAmazonDomainMap.put("en_IN", "amazon.co.uk"); + localeAmazonDomainMap.put("de", "amazon.de"); + localeAmazonDomainMap.put("es_ES", "amazon.es"); + localeAmazonDomainMap.put("es_MX", "amazon.com.mx"); + localeAmazonDomainMap.put("it", "amazon.it"); + localeAmazonDomainMap.put("pt_BR", DEFAULT_DOMAIN); + localeAmazonDomainMap.put("jp", "amazon.co.jp"); + localeAmazonDomainMap.put("fr_FR", "amazon.fr"); + localeAmazonDomainMap.put("fr_CA", "amazon.ca"); + localeAmazonDomainMap.put("hi_IN", "amazon.in"); + } + } + + public static String getLocalizedDomain(Locale locale) { + init(); + String domain = localeAmazonDomainMap.get(locale.toString()); + if (domain != null) { + return domain; + } else if (localeAmazonDomainMap.get(locale.getLanguage()) != null) { + return localeAmazonDomainMap.get(locale.getLanguage()); + } + return DEFAULT_DOMAIN; + } +} diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java similarity index 90% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java index 60324b78a..f89e399d0 100644 --- a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/ModuleProvider.java @@ -12,7 +12,7 @@ public class ModuleProvider { public static final String MODULES = "modules"; - public enum ModuleName { PREVIEW_MODE, ALEXA_CUSTOM_ASSISTANT, GEOLOCATION } + public enum ModuleName { PREVIEW_MODE, ALEXA_CUSTOM_ASSISTANT, GEOLOCATION, LVC } public static void addModule(@NonNull Context context, String module) { SharedPreferences.Editor editor = context.getSharedPreferences(MODULES, 0).edit(); @@ -64,4 +64,9 @@ public static boolean isAlexaCustomAssistantEnabled(@NonNull Context context) { String extraModules = getModules(context); return extraModules.contains(ModuleName.ALEXA_CUSTOM_ASSISTANT.name()); } + + public static boolean containsModule(@NonNull Context context, @NonNull ModuleName moduleName) { + String extraModules = getModules(context); + return extraModules.contains(moduleName.name()); + } } diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/NetworkUtil.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/NetworkUtil.java similarity index 96% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/NetworkUtil.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/NetworkUtil.java index 9a30737ed..1aa4f8ce9 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/NetworkUtil.java +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/NetworkUtil.java @@ -1,4 +1,4 @@ -package com.amazon.alexa.auto.setup.workflow.util; +package com.amazon.alexa.auto.apps.common.util; import android.content.Context; import android.net.ConnectivityManager; diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/Preconditions.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/Preconditions.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/Preconditions.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/Preconditions.java diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/UiThemeManager.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/UiThemeManager.java new file mode 100644 index 000000000..be0e8d50b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/UiThemeManager.java @@ -0,0 +1,315 @@ +package com.amazon.alexa.auto.apps.common.util; + +import android.content.Context; +import android.content.SharedPreferences; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.apis.apl.APLTheme; +import com.amazon.alexa.auto.apps.common.Constants; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.json.JSONException; +import org.json.JSONStringer; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * Manager class to handle ambient light sensor and Alexa Auto theme update. + */ +public class UiThemeManager { + private static final String TAG = UiThemeManager.class.getSimpleName(); + public static final String UI_MODE = "com.amazon.alexa.auto.uiMode"; + public static final String UI_LIGHT_THEME = "com.amazon.alexa.auto.ui.lightTheme"; + public static final String UI_DARK_THEME = "com.amazon.alexa.auto.ui.darkTheme"; + + // AACS Intent + public static final String AACS_INTENT_PAYLOAD_NAME = "name"; + public static final String AACS_INTENT_PAYLOAD_VALUE = "value"; + + // UI Modes + public static final String UI_MODE_KEY = "uiMode"; + public static final String UI_MODE_VALUE_DAY = "day"; + public static final String UI_MODE_VALUE_NIGHT = "night"; + + public static final String THEME_NAME = "theme"; + public static final String THEME_ID = "themeId"; + public static final String UI_MODE_VALUE_DARK = "dark"; + public static final String UI_MODE_VALUE_LIGHT = "light"; + public static final String THEME_VALUE_BLACK = "black"; + public static final String THEME_VALUE_GRAY = "gray"; + public static final String THEME_VALUE_GRAY_ONE = "gray1"; + public static final String THEME_VALUE_GRAY_TWO = "gray2"; + + APLThemeDirectiveReceiver mAPLThemeDirectiveReceiver; + + /** + * UI mode type. + */ + public enum UiModeType { + LIGHT(1), + DARK(2); + + private final int value; + + /** + * Enum constructor. + * + * @param newValue new enum value. + */ + UiModeType(final int newValue) { + value = newValue; + } + + /** + * Get enum value. + * + * @return integer value. + */ + public int getValue() { + return value; + } + + /** + * String value as lower case. + */ + @Override + public String toString() { + return name().toLowerCase(); + } + } + + private final Context mContext; + private final BehaviorSubject mUiModeUpdated; + + private SensorEventListener mSensorEventListener; + private UiModeType mCurrentAlsBasedMode; + + SensorManager mSensorManager; + AACSMessageSender mAACSMessageSender; + + private float mCurrentALSValue = -1; + + private static final float ALS_THRESHOLD_VALUE = 10.0f; + + public UiThemeManager(Context context, AACSMessageSender aacsMessageSender) { + mContext = context; + mUiModeUpdated = BehaviorSubject.createDefault(UiModeType.DARK); + mAACSMessageSender = aacsMessageSender; + } + + public void init() { + Log.i(TAG, "init"); + mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE); + mAPLThemeDirectiveReceiver = new APLThemeDirectiveReceiver(); + + EventBus.getDefault().register(mAPLThemeDirectiveReceiver); + + initAmbientLightSensor(); + } + + @VisibleForTesting + void init(SensorManager sensorManager) { + mSensorManager = sensorManager; + initAmbientLightSensor(); + } + + public void destroy() { + Log.i(TAG, "destroy"); + mSensorManager.unregisterListener(mSensorEventListener); + EventBus.getDefault().unregister(mAPLThemeDirectiveReceiver); + } + + public Observable getUiModeUpdatedObservable() { + return mUiModeUpdated; + } + + /** + * Init ambient light sensor. + */ + private void initAmbientLightSensor() { + Log.i(TAG, "initAmbientLightSensor"); + initSensorListener(); + + if (mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) != null) { + Log.i(TAG, "Device has ALS"); + Sensor ambientLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); + mSensorManager.registerListener(mSensorEventListener, ambientLightSensor, SensorManager.SENSOR_DELAY_UI); + } else { + Log.e(TAG, "Device has no ALS"); + } + } + + /** + * Init sensor listener. + */ + private void initSensorListener() { + mSensorEventListener = new SensorEventListener() { + @Override + public void onSensorChanged(SensorEvent sensorEvent) { + float value = sensorEvent.values[0]; + if (sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT) { + if (value > ALS_THRESHOLD_VALUE) { + if (mCurrentALSValue <= ALS_THRESHOLD_VALUE) { + Log.i(TAG, "setting day theme"); + mCurrentALSValue = value; + handleAlsUpdate(UiModeType.LIGHT); + } + } else { + if (mCurrentALSValue > ALS_THRESHOLD_VALUE || mCurrentALSValue == -1) { + Log.i(TAG, "setting night theme"); + mCurrentALSValue = value; + handleAlsUpdate(UiModeType.DARK); + } + } + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int i) {} + }; + } + + /** + * Handle ambient light sensor update. + * + * @param uiModeType @c ThemeType instance. + */ + void handleAlsUpdate(UiModeType uiModeType) { + Log.i(TAG, "handleAlsUpdate"); + if (uiModeType != getCurrentUIMode()) { + mCurrentAlsBasedMode = uiModeType; + mUiModeUpdated.onNext(uiModeType); + + saveCurrentUIMode(uiModeType); + saveAPLThemeProperties(uiModeType); + sendUiModeUpdate(uiModeType); + + sendThemeUpdate(uiModeType); + } + } + + /** + * Get current UI mode. + * + * @return UiModeType UI mode type. + */ + UiModeType getCurrentUIMode() { + if (mCurrentAlsBasedMode != null) { + return mCurrentAlsBasedMode; + } + + return UiModeType.DARK; + } + + private void saveCurrentUIMode(UiModeType uiMode) { + SharedPreferences.Editor editor = mContext.getSharedPreferences(UI_MODE, 0).edit(); + editor.putString(UI_MODE, uiMode.toString()); + editor.apply(); + } + + /** + * Update APL runtime property. + */ + private void sendUiModeUpdate(UiModeType uiMode) { + String payload; + try { + if (uiMode.equals(UiModeType.LIGHT)) { + payload = new JSONStringer() + .object() + .key(AACS_INTENT_PAYLOAD_NAME) + .value(UI_MODE_KEY) + .key(AACS_INTENT_PAYLOAD_VALUE) + .value(UI_MODE_VALUE_DAY) + .endObject() + .toString(); + } else if (uiMode.equals(UiModeType.DARK)) { + payload = new JSONStringer() + .object() + .key(AACS_INTENT_PAYLOAD_NAME) + .value(UI_MODE_KEY) + .key(AACS_INTENT_PAYLOAD_VALUE) + .value(UI_MODE_VALUE_NIGHT) + .endObject() + .toString(); + } else { + payload = null; + Log.e(TAG, "UI mode is invalid."); + } + + if (payload != null) { + mAACSMessageSender.sendMessage(Topic.APL, Action.APL.SET_PLATFORM_PROPERTY, payload); + } + } catch (JSONException e) { + Log.e(TAG, "Failed to parse UI mode payload."); + } + } + + private void sendThemeUpdate(UiModeType uiMode) { + String themeId = getSavedThemeId(uiMode); + try { + String payload = new JSONStringer() + .object() + .key(AACS_INTENT_PAYLOAD_NAME) + .value(THEME_ID) + .key(AACS_INTENT_PAYLOAD_VALUE) + .value(themeId) + .endObject() + .toString(); + mAACSMessageSender.sendMessage(Topic.APL, Action.APL.SET_PLATFORM_PROPERTY, payload); + } catch (JSONException e) { + Log.e(TAG, "Failed to parse UI theme payload."); + } + } + + String getSavedThemeId(UiModeType uiMode) { + SharedPreferences sharedPreferences = null; + if (uiMode.equals(UiModeType.LIGHT)) { + sharedPreferences = mContext.getSharedPreferences(UI_LIGHT_THEME, 0); + } else if (uiMode.equals(UiModeType.DARK)) { + sharedPreferences = mContext.getSharedPreferences(UI_DARK_THEME, 0); + } + + if (sharedPreferences != null) { + return sharedPreferences.getString(THEME_ID, ""); + } else { + return ""; + } + } + + /** + * Saving APL theme properties for rendering APL template with the updated APL theme. + * @param uiMode day/night mode + */ + private void saveAPLThemeProperties(UiModeType uiMode) { + String themeId = getSavedThemeId(uiMode); + SharedPreferences.Editor editor = mContext.getSharedPreferences(Constants.APL_RUNTIME_PROPERTIES, 0).edit(); + if (themeId.isEmpty()) { + editor.putString(THEME_NAME, uiMode.toString()); + } else { + editor.putString(THEME_NAME, uiMode + "-" + getSavedThemeId(uiMode)); + } + editor.apply(); + } + + /** + * Subscribe APL theme change and update APL runtime property. + */ + @VisibleForTesting + class APLThemeDirectiveReceiver { + @Subscribe + public void OnReceive(APLTheme theme) { + mAACSMessageSender.sendMessage(Topic.APL, Action.APL.SET_PLATFORM_PROPERTY, theme.getThemePayload()); + } + } +} diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/AlexaPropertyManager.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/AlexaPropertyManager.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/AlexaPropertyManager.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/AlexaPropertyManager.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/LocalesProvider.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/LocalesProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/LocalesProvider.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/main/java/com/amazon/alexa/auto/apps/common/util/config/LocalesProvider.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceControllerTest.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceControllerTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceControllerTest.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/aacs/AACSServiceControllerTest.java diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/FileUtilTest.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/FileUtilTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/FileUtilTest.java rename to aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/FileUtilTest.java diff --git a/aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/UiThemeManagerTest.java b/aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/UiThemeManagerTest.java new file mode 100644 index 000000000..d13a6e9ca --- /dev/null +++ b/aacs/android/app-components/alexa-auto-apps-common-util/src/test/java/com/amazon/alexa/auto/apps/common/util/UiThemeManagerTest.java @@ -0,0 +1,128 @@ +package com.amazon.alexa.auto.apps.common.util; + +import android.content.Context; +import android.content.SharedPreferences; +import android.hardware.SensorManager; + +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; + +import org.greenrobot.eventbus.EventBus; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.robolectric.RobolectricTestRunner; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.observers.TestObserver; + +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_ID; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_VALUE_BLACK; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.THEME_VALUE_GRAY_ONE; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_DARK_THEME; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_LIGHT_THEME; +import static com.amazon.alexa.auto.apps.common.util.UiThemeManager.UI_MODE; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; + +@RunWith(RobolectricTestRunner.class) +public class UiThemeManagerTest { + private Context mockContext; + private SensorManager mockSensorManager; + private AACSMessageSender mockAACSMessageSender; + private UiThemeManager uiThemeManager; + private SharedPreferences mLightModeSharedPrefs; + private SharedPreferences mDarkModeModeSharedPrefs; + private SharedPreferences mUIModeSharedPrefs; + private SharedPreferences.Editor mEditor; + private EventBus eventBus; + private UiThemeManager.APLThemeDirectiveReceiver mAPLThemeDirectiveReceiver; + + @Before + public void setup() { + mockContext = Mockito.mock(Context.class); + mockSensorManager = Mockito.mock(SensorManager.class); + mockAACSMessageSender = Mockito.mock(AACSMessageSender.class); + uiThemeManager = new UiThemeManager(mockContext, mockAACSMessageSender); + mAPLThemeDirectiveReceiver = Mockito.mock(UiThemeManager.APLThemeDirectiveReceiver.class); + mLightModeSharedPrefs = Mockito.mock(SharedPreferences.class); + mDarkModeModeSharedPrefs = Mockito.mock(SharedPreferences.class); + mUIModeSharedPrefs = Mockito.mock(SharedPreferences.class); + mEditor = Mockito.mock(SharedPreferences.Editor.class); + Mockito.when(mockContext.getSharedPreferences(eq(UI_MODE), anyInt())).thenReturn(mUIModeSharedPrefs); + Mockito.when(mockContext.getSharedPreferences(eq(UI_LIGHT_THEME), anyInt())).thenReturn(mLightModeSharedPrefs); + Mockito.when(mockContext.getSharedPreferences(eq(UI_DARK_THEME), anyInt())).thenReturn(mDarkModeModeSharedPrefs); + Mockito.when(mLightModeSharedPrefs.edit()).thenReturn(mEditor); + Mockito.when(mDarkModeModeSharedPrefs.edit()).thenReturn(mEditor); + Mockito.when(mUIModeSharedPrefs.edit()).thenReturn(mEditor); + EventBus.getDefault().register(mAPLThemeDirectiveReceiver); + eventBus = spy(EventBus.getDefault()); + } + + @Test + public void test_handle_ui_mode_light() { + uiThemeManager.init(mockSensorManager); + + //Act + uiThemeManager.handleAlsUpdate(UiThemeManager.UiModeType.LIGHT); + + //Verify + Assert.assertEquals(UiThemeManager.UiModeType.LIGHT, uiThemeManager.getCurrentUIMode()); + } + + @Test + public void test_handle_ui_mode_dark() { + uiThemeManager.init(mockSensorManager); + + //Act + uiThemeManager.handleAlsUpdate(UiThemeManager.UiModeType.DARK); + + //Verify + Assert.assertEquals(UiThemeManager.UiModeType.DARK, uiThemeManager.getCurrentUIMode()); + } + + @Test + public void test_handle_ui_theme_in_dark_mode() { + uiThemeManager.init(mockSensorManager); + Mockito.when(mDarkModeModeSharedPrefs.getString(THEME_ID, "")).thenReturn(THEME_VALUE_BLACK); + + //Act + uiThemeManager.handleAlsUpdate(UiThemeManager.UiModeType.DARK); + + //Verify + Assert.assertEquals(THEME_VALUE_BLACK, uiThemeManager.getSavedThemeId(UiThemeManager.UiModeType.DARK)); + } + + @Test + public void test_handle_ui_theme_in_light_mode() { + uiThemeManager.init(mockSensorManager); + Mockito.when(mLightModeSharedPrefs.getString(THEME_ID, "")).thenReturn(THEME_VALUE_GRAY_ONE); + + //Act + uiThemeManager.handleAlsUpdate(UiThemeManager.UiModeType.LIGHT); + + //Verify + Assert.assertEquals(THEME_VALUE_GRAY_ONE, uiThemeManager.getSavedThemeId(UiThemeManager.UiModeType.LIGHT)); + } + + @Test + public void test_get_ui_mode_update_observable() { + uiThemeManager.init(mockSensorManager); + + Observable uiModeUpdatedObservable = uiThemeManager.getUiModeUpdatedObservable(); + TestObserver testObserver = TestObserver.create(); + uiModeUpdatedObservable.subscribe(testObserver); + testObserver.assertValue(UiThemeManager.UiModeType.DARK); + + //Act + uiThemeManager.handleAlsUpdate(UiThemeManager.UiModeType.LIGHT); + + //Verify + testObserver = TestObserver.create(); + uiModeUpdatedObservable.subscribe(testObserver); + testObserver.assertValue(UiThemeManager.UiModeType.LIGHT); + Assert.assertEquals(UiThemeManager.UiModeType.LIGHT, uiThemeManager.getCurrentUIMode()); + } +} diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/src/test/resources/aacs_config.json b/aacs/android/app-components/alexa-auto-apps-common-util/src/test/resources/aacs_config.json similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/src/test/resources/aacs_config.json rename to aacs/android/app-components/alexa-auto-apps-common-util/src/test/resources/aacs_config.json diff --git a/platforms/android/app-components/alexa-auto-carcontrol/.gitignore b/aacs/android/app-components/alexa-auto-carcontrol/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/.gitignore rename to aacs/android/app-components/alexa-auto-carcontrol/.gitignore diff --git a/aacs/android/app-components/alexa-auto-carcontrol/README.md b/aacs/android/app-components/alexa-auto-carcontrol/README.md new file mode 100644 index 000000000..cacd98c22 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-carcontrol/README.md @@ -0,0 +1,206 @@ +# AACS Car Control +The AACS Car Control library is an Android library for the AACS Core Service to run car control commands in cars that are based on Android Automotive OS. A car control command is run by the AACS Core Service each time the user tries to voice-control a vehicle component. + + +## Table of Contents +- [Overview](#overview) +- [Understanding Library Components](#understanding-library-components) +- [Building the AACS Car Control Library](#building-the-aacs-car-control-library) +- [Before Using the AACS Car Control Library](#before-using-the-aacs-car-control-library) + - [Including AACS Car Control Library in a System Application](#including-aacs-car-control-library-in-a-system-application) + - [Providing Permission in Android Manifest](#providing-permission-in-android-manifest) + - [Ensuring Intent Target Specified in the Library is Used](#ensuring-intent-target-specified-in-the-library-is-used) +- [Sequence Diagrams](#sequence-diagrams) +- [How the AACS Car Control Library Works](#how-the-aacs-car-control-library-works) + +## Overview +Using the AACS Car Control Library, AACS allows user utterances to be directly applied to Android Automotive OS car control APIs and then to the Hardware Abstraction Layer to complete the car control workflow. The library translates between Auto SDK Car Control events and Android Automotive `CarPropertyManager` API calls, which controls various car features, such as air conditioning and fan settings. For information about `CarPropertyManager`, see the [Android documentation on CarPropertyManager](https://developer.android.com/reference/android/car/hardware/property/CarPropertyManager). + +The library works with Android [Car API](https://developer.android.com/reference/android/car/Car) and [CarPropertyManager API](https://developer.android.com/reference/android/car/hardware/property/CarPropertyManager). These APIs are only available at Android API level 29 and up. + +The library is an optional module. You can build it into an Android archive (AAR) to be included in your application. + +## Understanding Library Components + +The following list describes the purposes of the major components of the library: + +* The AACS Car Control Broadcast Receiver: + * Receiving AASB `AdjustControllerValue` or `SetControllerValue` messages from the AACS Core Service. + * Instantiating the Car Control Handler to call specific controller operations. The exact operations supported depend on the controller type, which can be Power, Toggle, Mode, or Range. + +* The AACS Car Control platform implementation (`CarControlHandler`): + * Instantiating the Android Car object to be called in the set and adjust methods for each controller type. + * Defining the get and set methods for each controller type. + * Defining the adjust methods for the Range or Power Controller. + +* The AACS Car Control Helper/Util: + * Providing translation between [endpointID, controllerType, controllerID, value] in the AASB Car Control message from the Auto SDK Engine to [propertyId, areaId, value] used in the Android Automotive API call. + * Getting or saving the current Mode setting for the Mode Controller. + * Enabling you to parse an external configuration file if you want to use a customized `CarControlEndpointMapping.json` file. + +* Car Control Endpoint Mapping configuration file maps [endpointID, controllerType, controllerID, value] from the Auto SDK Car Control Asset to [propertyId, areaId, value] used in the Android Automotive API call. + + A default `CarControlEndpointMapping.json` file is provided in the assets directory. Be sure to review `CarControlEndpointMapping.json` to verify that it contains values consistent with the ones specified in the [CarControlConfig.json file in the Car Control module](../../../../modules/car-control/assets/CarControlConfig.json). For example, if you have changed an `endpointId` in `CarControlConfig.json` from `"default.light"` to `"default.roof.light"`, the `CarControlEndpointMapping.json` file must contain the same endpoint mapping information. + +## Building the AACS Car Control Library +You can build the library locally using the following steps: + 1) Enter the following command to change the directory: + ~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app + ~~~ + 2) Enter the following command to build the Car Control library: + ~~~ + ./gradlew :alexa-auto-carcontrol:assembleRelease + ~~~ + Replace `assembleRelease` with `assembleDebug` if you want to build the debug version of the library. The generated AAR is available at `alexa-auto-sdk/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/build/outputs/aar`. + You must include the `AACSIPC`, `AACSConstants`, `AACSCommonUtils`, `AACS` and `Auto SDK` AARs in your application to use with the AACS Car Control AAR. + +To enable car control support in the AACS Sample App, follow these steps: +1) Enter the following command to change the directory: +~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app +~~~ +2) Enter the following command to start the local build with car control enabled. +~~~ + ./gradlew assembleLocalRelease -PenabledCarControl +~~~ +For more build options, see the [AACS Sample App README](../../sample-app/README.md#optional-arguments). + +## Before Using the AACS Car Control Library +Before using the library, follow these major steps: + +1) Install your application with the AACS and Car Control AARs as a system privileged app on Android Automotive OS. +2) Provide permission in your app's Android Manifest. +3) Ensure that the intent target specified in the library is used. + +### Including AACS Car Control Library in a System Application +For AACS to enable the permission namespace `android.car.permission`, it must run in a system privileged app. To install your application as a system privileged app, place it in the `/system/priv-app/` directory. + +### Providing Permission in Android Manifest +For security reasons, for your application to send intents to or receive intents from the AACS Car Control Library, follow these steps: + +1) In `privapp-permissions-com.amazon.alexaautoclientservice.xml`, specify `android.car.permission`. The following example file shows how to specify permissions for using intents for various car control operations. + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +2) Include `privapp-permissions-com.amazon.alexaautoclientservice.xml` in the `/etc/permissions/` directory. + +### Ensuring Intent Target Specified in the Library is Used +The AACS Car Control Broadcast Receiver listens to intents from the AACS Core Service with the `CarControl` topic. The intent filter in the AACS Car Control Library already defines the intent target for `CarControl`. For the intent filter in the library to take effect, be sure to clear the intent target defined for `CarControl` in the AACS configuration as follows. Otherwise, the target specification in the AACS configuration overrides the intent filter in the library. + +```json + "CarControl" : { + "type": [], + "package": [], + "class": [] + } +``` + +## Sequence Diagrams +The following diagram illustrates the flow when an utterance asks Alexa to set fan speed to 3. +

+ +

+ +The following diagram illustrates the flow after the set value is finished at the hardware layer. +

+ +

+ +## How the AACS Car Control Library Works +When the user issues an utterance, the Engine receives a car control event from Alexa, which the Engine passes to AACS through an AASB message. + +The AASB message received by AACS has the following attributes: + +* Action is `com.amazon.aacs.aasb.AdjustControllerValue` or `com.amazon.aacs.aasb.SetControllerValue`. +* Category is `com.amazon.aacs.aasb.CarControl`. +* Extras is `payload`. + + The `payload` object includes detailed information about the action, which is specified in the `messageDescription` field of the AASB message. The following list describes the `payload` for each action: + * For `SetControllerValue`, the payload has the following schema: + ``` + "payload" : { + "controllerType" : "POWER", + "endpointId" : "{{String}}", + "turnOn" : {{Boolean}} + } + ``` + * For `AdjustControllerValue`, the payload has the following schema: + ``` + "payload" : { + "controllerType" : "TOGGLE", + "endpointId" : "{{String}}", + "controllerId" : "{{String}}", + "turnOn" : {{Boolean}} + } + ``` + * For `SetModeController`, the payload has the following schema: + ``` + "payload" : { + "controllerType" : "MODE", + "endpointId" : "{{String}}", + "controllerId" : "{{String}}", + "value" : "{{String}}" + } + ``` + * For `SetRangeController`, the payload has the following schema: + ``` + "payload" : { + "controllerType" : "RANGE", + "endpointId" : "{{String}}", + "controllerId" : "{{String}}", + "value" : {{Double}} + } + ``` + * For `AdjustModeController`, the payload has the following schema: + ``` + "payload" : { + "controllerType" : "MODE", + "endpointId" : "{{String}}", + "controllerId" : "{{String}}", + "delta" : {{Integer}} + } + ``` + * For `AdjustRangeController`, the payload has the following schema: + ``` + "payload" : { + "controllerType" : "RANGE", + "endpointId" : "{{String}}", + "controllerId" : "{{String}}", + "delta" : {{Double}} + } + ``` + +After receiving the intent, the AACS Car Control Broadcast Receiver parses the payload and calls for the Car Control Handler to perform specific car control operations. diff --git a/extensions/system-audio/modules/system-audio/lib/aal/.gitignore b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/.gitignore similarity index 100% rename from extensions/system-audio/modules/system-audio/lib/aal/.gitignore rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/.gitignore diff --git a/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/build.gradle b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/build.gradle new file mode 100644 index 000000000..0a553c50b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/build.gradle @@ -0,0 +1,60 @@ +plugins { + id 'com.android.library' +} + +android { + compileSdkVersion 29 + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 29 + versionCode 1 + versionName "4.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' + useLibrary 'android.car' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests { + includeAndroidResources = true + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.aar']) + implementation project(':aacsconstants') + implementation project(':aacscommonutils') + implementation project(':aacsipc') + + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.3.0' + testImplementation 'junit:junit:4.12' + testImplementation 'androidx.test:runner:1.1.0' + testImplementation 'androidx.test:core:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test:rules:1.1.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.0' + androidTestImplementation 'androidx.test:monitor:1.1.1' + androidTestImplementation 'org.mockito:mockito-android:2.22.0' + testImplementation 'org.mockito:mockito-core:1.10.19' + testImplementation 'org.powermock:powermock-api-mockito:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4:1.6.2' + testImplementation 'org.powermock:powermock-api-easymock:2.0.9' + testImplementation 'org.robolectric:annotations:4.3' +} \ No newline at end of file diff --git a/platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra/proguard-rules.pro b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/proguard-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/assets/CarControlEndpointMapping.json b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/assets/CarControlEndpointMapping.json similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/assets/CarControlEndpointMapping.json rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/assets/CarControlEndpointMapping.json diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/AACSCarControlReceiver.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/AACSCarControlReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/AACSCarControlReceiver.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/AACSCarControlReceiver.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlConstants.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlConstants.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlConstants.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlConstants.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHandler.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHandler.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHandler.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHelper.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHelper.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHelper.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlHelper.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlUtil.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlUtil.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/main/java/com/amazon/aacscarcontrol/CarControlUtil.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHandlerTests.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHandlerTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHandlerTests.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHandlerTests.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHelperTests.java b/aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHelperTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHelperTests.java rename to aacs/android/app-components/alexa-auto-carcontrol/aacscarcontrol/src/test/java/com/amazon/aacscarcontrol/CarControlHelperTests.java diff --git a/platforms/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.png b/aacs/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.png similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.png rename to aacs/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.png diff --git a/platforms/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.puml b/aacs/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.puml similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.puml rename to aacs/android/app-components/alexa-auto-carcontrol/assets/set-fan-speed-to-3.puml diff --git a/platforms/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.png b/aacs/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.png similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.png rename to aacs/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.png diff --git a/platforms/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.puml b/aacs/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.puml similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.puml rename to aacs/android/app-components/alexa-auto-carcontrol/assets/set-reply-to-engine.puml diff --git a/aacs/android/app-components/alexa-auto-carcontrol/build.gradle b/aacs/android/app-components/alexa-auto-carcontrol/build.gradle new file mode 100644 index 000000000..d17de9ba2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-carcontrol/build.gradle @@ -0,0 +1,46 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.versions = [ + 'kotlin': '1.4.0', + 'moshi': '1.9.3', + + // Test Dependencies + 'mockito': '3.4.0', + ] + + ext.deps = [ + 'kotlin_stdlib': "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}", + 'junit': 'junit:junit:4.12', + 'androidx_test_core': 'androidx.test:core:1.1.0', + 'androidx_test_monitor': "androidx.test:monitor:1.1.1", + 'androidx_annotation': "androidx.annotation:annotation:1.1.0", + 'moshi': "com.squareup.moshi:moshi:${versions.moshi}", + 'moshi_codegen': "com.squareup.moshi:moshi-kotlin-codegen:${versions.moshi}", + 'mockito': "org.mockito:mockito-core:${versions.mockito}", + 'roboelectric': 'org.robolectric:robolectric:4.3' + ] + + repositories { + google() + mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/extensions/bluetooth/aacs/android/gradle.properties b/aacs/android/app-components/alexa-auto-carcontrol/gradle.properties similarity index 100% rename from extensions/bluetooth/aacs/android/gradle.properties rename to aacs/android/app-components/alexa-auto-carcontrol/gradle.properties diff --git a/aacs/android/app-components/alexa-auto-carcontrol/settings.gradle b/aacs/android/app-components/alexa-auto-carcontrol/settings.gradle new file mode 100644 index 000000000..8a684f7b8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-carcontrol/settings.gradle @@ -0,0 +1,9 @@ +rootProject.name='alexa-auto-carcontrol' +include ':aacscarcontrol' +gradle.ext.aacsRoot = '../..' +include ':aacsconstants' +project(':aacsconstants').projectDir = new File(gradle.ext.aacsRoot, '/common/constants/aacsconstants') +include ':aacsipc' +project(':aacsipc').projectDir = new File(gradle.ext.aacsRoot, '/common/ipc/aacsipc') +include ':aacscommonutils' +project(':aacscommonutils').projectDir = new File(gradle.ext.aacsRoot, '/common/commonutils/aacscommonutils') diff --git a/platforms/android/app-components/alexa-auto-comms-ui/.gitignore b/aacs/android/app-components/alexa-auto-comms-ui/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/.gitignore rename to aacs/android/app-components/alexa-auto-comms-ui/.gitignore diff --git a/aacs/android/app-components/alexa-auto-comms-ui/README.md b/aacs/android/app-components/alexa-auto-comms-ui/README.md new file mode 100644 index 000000000..3b5145d7c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/README.md @@ -0,0 +1,28 @@ +# Alexa Auto Comms UI + +This library serves the following purposes: + +* It handles Bluetooth-related directives. + When a Bluetooth device is connected or disconnected, the `BluetoothReceiver` class receives the intent with device connection status, and device MAC address and display name. It also calls the `BluetoothDirectiveHandler` class to update the Bluetooth device database based on the change. + +* It handles contacts upload or removal requests to Alexa. + This library starts the AACS contacts service intents to handle contacts upload or removal requests. + +* Alexa setup screen provides options for the user to give or decline consent to contact uploads on the primary phone. + +* The Alexa communication settings screen displays a list of connected devices with contacts upload permission status. The user can turn on or turn off the contacts upload permission for each device. If the contacts permission for the primary phone is enabled, the contacts in that device will be uploaded. If the contacts permission for a non-primary phone is enabled, the contacts in that phone will not be uploaded until the phone is selected as the primary. + +On the Android Automotive OS, the last connected phone is considered as the primary device. If you want to change this default behavior, implement your own system UI for users to select the primary phone and call the Android system API `setUserSelectedOutgoingPhoneAccount` to set the user-selected outgoing phone account. Send a `com.amazon.alexa.auto.comms.primaryPhoneChanged` intent to Alexa Auto Comms UI to inform the change of the primary phone. +``` +ComponentName c = new ComponentName("com.amazon.alexa.auto.app", "com.amazon.alexa.auto.comms.ui.receiver.BluetoothReceiver"); +intent.setComponent(c); +intent.addCategory("com.amazon.alexa.auto.comms"); +intent.setAction("com.amazon.alexa.auto.comms.primaryPhoneChanged"); +sendBroadcast(intent); +``` + + +## Prerequisites +The following list describes the prerequisites for this library: +* AACS Telephony and Contacts libraries must be built. +* Your Android device must meet the prerequisites for using the [AACS Telephony library](../alexa-auto-telephony/README.md#prerequisites). \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-comms-ui/build.gradle b/aacs/android/app-components/alexa-auto-comms-ui/build.gradle new file mode 100644 index 000000000..d3deae815 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/build.gradle @@ -0,0 +1,81 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-comms-ui" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(':aacscommonutils') + implementation project(':aacsconstants') + implementation project(':alexa-auto-apis') + implementation project(':alexa-auto-setup') + implementation project(':alexa-auto-apps-common-util') + + implementation deps.androidx_appcompat + implementation deps.androidx_preference + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + + // RX + implementation deps.rxjava3 + + // Dagger + implementation deps.dagger + annotationProcessor 'com.google.dagger:dagger-compiler:2.22' + + //Eventbus + implementation deps.eventbus + + // Database + implementation "androidx.room:room-runtime:2.2.6" + annotationProcessor "androidx.room:room-compiler:2.2.6" + + // Navigation between UI components. + implementation deps.androidx_navigation_fragment + implementation deps.androidx_navigation_ui + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.androidx_test_core + testImplementation deps.androidx_arch_core_testing + testImplementation deps.androidx_fragment_testing + testImplementation deps.roboelectric +} diff --git a/platforms/android/app-components/alexa-auto-apis/proguard-rules.pro b/aacs/android/app-components/alexa-auto-comms-ui/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-apis/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-comms-ui/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/AndroidManifest.xml new file mode 100644 index 000000000..b4d040ddc --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/AndroidManifest.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/Constants.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/Constants.java new file mode 100644 index 000000000..5ea8ba7ae --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/Constants.java @@ -0,0 +1,34 @@ +package com.amazon.alexa.auto.comms.ui; + +public class Constants { + // State + public static final String BT_CONNECTED = "CONNECTED"; + public static final String BT_DISCONNECTED = "DISCONNECTED"; + public static final String CONTACTS_PERMISSION_YES = "YES"; + public static final String CONTACTS_PERMISSION_NO = "NO"; + + // AACS Bluetooth intents + public final static String AACS_BT_DEVICE_ADDRESS = "deviceAddress"; + public final static String AACS_BT_DEVICE_NAME = "deviceName"; + public static final String AACS_TELEPHONY_SERVICE = "com.amazon.aacstelephony"; + public static final String AACS_BT_CONNECTED = "com.amazon.aacstelephony.bluetooth.connected"; + public static final String AACS_BT_DISCONNECTED = "com.amazon.aacstelephony.bluetooth.disconnected"; + public static final String AACS_BT_CONNECTION_CHECK_COMPLETED = "com.amazon.aacstelephony.bluetooth.connectionCheckCompleted"; + + // AACS Contacts intents + public final static String AACS_CONTACTS_SERVICE = "com.amazon.aacscontacts.AACSContactsService"; + public static final String AACS_ACTION_UPLOAD_CONTACTS = "com.amazon.aacscontacts.upload"; + public static final String AACS_ACTION_REMOVE_CONTACTS = "com.amazon.aacscontacts.remove"; + public static final String AACS_EXTRA_ADDRESSBOOK_ID = "addressBookSourceId"; + public static final String AACS_EXTRA_ADDRESSBOOK_NAME_KEY = "addressBookName"; + public static final String AACS_EXTRA_ADDRESSBOOK_NAME_VALUE = "PhoneBook"; + + // Alexa Auto Comms intents + public final static String ALEXA_AUTO_COMMS = "com.amazon.alexa.auto.comms"; + public final static String ALEXA_AUTO_COMMS_PRIMARY_PHONE_CHANGED = "com.amazon.alexa.auto.comms.primaryPhoneChanged"; + + // Communication + public static final String COMMUNICATION_PERMISSION_ENABLED = "enabled"; + public static final String COMMUNICATION_PERMISSION_DISABLED = "disabled"; + public static final String COMMUNICATION_DEVICE_ADDRESS = "deviceAddress"; +} diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/ContactsControllerImpl.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/ContactsControllerImpl.java new file mode 100644 index 000000000..16b76658e --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/ContactsControllerImpl.java @@ -0,0 +1,236 @@ +package com.amazon.alexa.auto.comms.ui; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ServiceInfo; +import android.os.Handler; +import android.os.Looper; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.lifecycle.LiveData; + +import com.amazon.aacsconstants.AACSConstants; +import com.amazon.alexa.auto.apis.communication.ContactsController; +import com.amazon.alexa.auto.comms.ui.db.BTDevice; +import com.amazon.alexa.auto.comms.ui.db.BTDeviceRepository; +import com.amazon.alexa.auto.comms.ui.db.ConnectedBTDevice; +import com.amazon.alexa.auto.comms.ui.db.ConnectedBTDeviceRepository; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import java.lang.ref.WeakReference; +import java.util.concurrent.Executor; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +import static com.amazon.alexa.auto.comms.ui.Constants.CONTACTS_PERMISSION_NO; +import static com.amazon.alexa.auto.comms.ui.Constants.CONTACTS_PERMISSION_YES; + +public class ContactsControllerImpl implements ContactsController { + private static final String TAG = ContactsControllerImpl.class.getSimpleName(); + private static String _AACS_CONTACTS_PACKAGE_NAME = null; // This should remain private non final + + private final WeakReference mContextWk; + private final BTDeviceRepository mBTDeviceRepository; + private final ConnectedBTDeviceRepository mConnectedBTDeviceRepository; + private final BehaviorSubject mContactsUploadConsentSubject; + private String mPrimaryDeviceAddress = ""; + private final ScheduledExecutorService mExecutor; + + /** + * Constructs an instance of ContactsControllerImpl. + * + * @param contextWk Android Context. + */ + public ContactsControllerImpl(@NonNull WeakReference contextWk) { + mContextWk = contextWk; + mBTDeviceRepository = BTDeviceRepository.getInstance(mContextWk.get()); + mConnectedBTDeviceRepository = ConnectedBTDeviceRepository.getInstance(mContextWk.get()); + mContactsUploadConsentSubject = BehaviorSubject.create(); + mExecutor = Executors.newSingleThreadScheduledExecutor(); + if (!EventBus.getDefault().isRegistered(this)) { + EventBus.getDefault().register(this); + } + } + + @Override + public void uploadContacts(String deviceAddress) { + String aacsContactsPackageName = getAACSContactsPackageName(mContextWk); + if (aacsContactsPackageName == null) { + Log.e(TAG, "AACS contacts service is not available, skip to upload contacts."); + } else if (!mPrimaryDeviceAddress.equals(deviceAddress)) { + Log.i(TAG, "The device provided is not set to primary, skip to upload contacts. " + + "The current primary device is " + mPrimaryDeviceAddress); + } else { + Log.d(TAG, "Uploading contacts..."); + Intent intentStartService = new Intent(); + intentStartService.setComponent( + new ComponentName(aacsContactsPackageName, Constants.AACS_CONTACTS_SERVICE)); + intentStartService.setAction(Constants.AACS_ACTION_UPLOAD_CONTACTS); + intentStartService.putExtra(Constants.AACS_EXTRA_ADDRESSBOOK_ID, deviceAddress); + intentStartService.putExtra( + Constants.AACS_EXTRA_ADDRESSBOOK_NAME_KEY, Constants.AACS_EXTRA_ADDRESSBOOK_NAME_VALUE); + startAACSService(mContextWk.get(), intentStartService); + } + } + + @Override + public void removeContacts(String deviceAddress) { + Log.d(TAG, "Removing contacts..."); + String aacsContactsPackageName = getAACSContactsPackageName(mContextWk); + if (aacsContactsPackageName != null) { + Intent intentStartService = new Intent(); + intentStartService.setComponent( + new ComponentName(aacsContactsPackageName, Constants.AACS_CONTACTS_SERVICE)); + intentStartService.setAction(Constants.AACS_ACTION_REMOVE_CONTACTS); + intentStartService.putExtra(Constants.AACS_EXTRA_ADDRESSBOOK_ID, deviceAddress); + startAACSService(mContextWk.get(), intentStartService); + } else { + Log.e(TAG, "AACS contacts service is not available, skip to remove contacts."); + } + } + + @Override + public void setContactsUploadPermission(String deviceAddress, String permission) { + mBTDeviceRepository.getBTDeviceByAddress(deviceAddress); + mBTDeviceRepository.updateContactsPermission(deviceAddress, permission); + mConnectedBTDeviceRepository.updateContactsPermission(deviceAddress, permission); + } + + @Override + public Observable observeContactsConsent() { + mBTDeviceRepository.findPrimaryBTDeviceEntry(); + return mContactsUploadConsentSubject; + } + + @Subscribe + public void onBTDeviceDiscoveryChange(BTDeviceRepository.BTDeviceDiscoveryMessage message) { + if (message.isFound()) { + Log.d(TAG, "Bluetooth device is found."); + + BTDevice device = message.getBTDevice(); + if (message.getBTDevice().getContactsUploadPermission().equals(Constants.CONTACTS_PERMISSION_NO)) { + mContactsUploadConsentSubject.onNext(true); + } else { + mContactsUploadConsentSubject.onNext(false); + uploadContacts(device.getDeviceAddress()); + } + } else { + Log.d(TAG, "Bluetooth device is not found, skipping contacts upload consent step."); + mContactsUploadConsentSubject.onNext(false); + } + } + + @Subscribe + public void onConnectedBTDeviceDiscoveryChange( + ConnectedBTDeviceRepository.ConnectedBTDeviceDiscoveryMessage connectedDeviceDiscoveryMessage) { + if (connectedDeviceDiscoveryMessage.isFound()) { + Log.d(TAG, + "Device " + connectedDeviceDiscoveryMessage.getBConnectedBTDevice().getDeviceAddress() + + " is disconnected, remove it from connected device database."); + mConnectedBTDeviceRepository.deleteEntry(connectedDeviceDiscoveryMessage.getBConnectedBTDevice()); + removeContacts(connectedDeviceDiscoveryMessage.getBConnectedBTDevice().getDeviceAddress()); + } + } + + @Subscribe + public void onPrimaryPhoneChange( + ConnectedBTDeviceRepository.PrimaryPhoneChangeMessage primaryPhoneChangeMessage) { + updatePrimaryDeviceAddress(primaryPhoneChangeMessage.getConnectedBTDevice(), primaryPhoneChangeMessage.getIsNewDevice()); + } + + /** + * Start AACS service with intent. + * @param context Android context. + * @param intent Android intent. + */ + private void startAACSService(Context context, Intent intent) { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + context.startForegroundService(intent); + } else { + context.startService(intent); + } + } + + /** + * This method returns the package name of AACS Contacts Service dynamically. + * If AACS Contacts Service is running in AACS as separate application, it returns value of AACS package name. + * Otherwise if AACS Contacts Service is included in the client app as an AAR, it returns the client app + * package name. + * @param contextWk Weak reference of Android context for getting a package manager + * @return AACS Contacts Service package name + */ + private String getAACSContactsPackageName(@NonNull WeakReference contextWk) { + if (_AACS_CONTACTS_PACKAGE_NAME == null) { + PackageManager packageManager = contextWk.get().getPackageManager(); + try { + _AACS_CONTACTS_PACKAGE_NAME = AACSConstants.getAACSPackageName(contextWk); + PackageInfo packageInfo = + packageManager.getPackageInfo(contextWk.get().getPackageName(), PackageManager.GET_SERVICES); + for (ServiceInfo serviceInfo : packageInfo.services) { + if (serviceInfo.name.equals(Constants.AACS_CONTACTS_SERVICE)) { + _AACS_CONTACTS_PACKAGE_NAME = contextWk.get().getPackageName(); + Log.d(TAG, String.format("Setting PACKAGE_NAME %s", _AACS_CONTACTS_PACKAGE_NAME)); + break; + } + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Failed to find AACS contacts package information in package manager."); + return null; + } + } + return _AACS_CONTACTS_PACKAGE_NAME; + } + + private void updatePrimaryDeviceAddress(ConnectedBTDevice device, boolean isNewDevice) { + String deviceAddress = device == null ? "" : device.getDeviceAddress(); + String permission = device == null ? CONTACTS_PERMISSION_NO : device.getContactsUploadPermission(); + + if (mPrimaryDeviceAddress.equals(deviceAddress)) { + Log.d(TAG, "The primary phone has not changed: " + mPrimaryDeviceAddress); + return; + } + + String outdatedDeviceAddress = mPrimaryDeviceAddress; + mPrimaryDeviceAddress = deviceAddress; + + if (!outdatedDeviceAddress.isEmpty()) { + Log.d(TAG, "removing the previously uploaded address book from " + outdatedDeviceAddress); + removeContacts(outdatedDeviceAddress); + } + + if (permission.equals(CONTACTS_PERMISSION_YES)) { + if (!isNewDevice) { + Log.d(TAG, "Upload the address book from the primary phone " + deviceAddress); + uploadContacts(deviceAddress); + } else { + Log.d(TAG, "Schedule uploading address book after 30s from the primary phone " + deviceAddress); + mExecutor.schedule(() -> { + // check the permission again before uploading the contacts + Log.d(TAG, "start uploading address book from the primary phone " + deviceAddress); + ConnectedBTDevice primaryDevice = mConnectedBTDeviceRepository.getConnectedDeviceByAddressSync(deviceAddress); + if (primaryDevice != null && + CONTACTS_PERMISSION_YES.equals(primaryDevice.getContactsUploadPermission())) { + Log.d(TAG, "Uploading the address book from the primary phone " + deviceAddress); + uploadContacts(deviceAddress); + } else { + Log.d(TAG, "address book uploading cancelled."); + } + }, 30, TimeUnit.SECONDS); + } + } + } +} diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/PreferenceKeys.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/PreferenceKeys.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/PreferenceKeys.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/PreferenceKeys.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDevice.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDevice.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDevice.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDevice.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDao.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDao.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDao.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDao.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDatabase.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDatabase.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDatabase.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceDatabase.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceRepository.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceRepository.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceRepository.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/BTDeviceRepository.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDevice.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDevice.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDevice.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDevice.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDao.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDao.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDao.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDao.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDatabase.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDatabase.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDatabase.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceDatabase.java diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceRepository.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceRepository.java new file mode 100644 index 000000000..923e3565b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/db/ConnectedBTDeviceRepository.java @@ -0,0 +1,198 @@ +package com.amazon.alexa.auto.comms.ui.db; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; + +import androidx.lifecycle.LiveData; +import androidx.room.Room; + +import org.greenrobot.eventbus.EventBus; + +import java.util.List; + +public class ConnectedBTDeviceRepository { + private String CONNECTED_DB_NAME = "db_connected_bt_device"; + private String DB_NAME = "db_bt_device"; + private ConnectedBTDeviceDatabase connectedBTDeviceDatabase; + private BTDeviceDatabase btDeviceDatabase; + private Handler mHandler; + + private static ConnectedBTDeviceRepository sInstance; + private String TAG = ConnectedBTDeviceRepository.class.getSimpleName(); + + public static ConnectedBTDeviceRepository getInstance(Context context) { + if (sInstance == null) { + sInstance = new ConnectedBTDeviceRepository(context); + } + return sInstance; + } + + private ConnectedBTDeviceRepository(Context context) { + connectedBTDeviceDatabase = + Room.databaseBuilder(context, ConnectedBTDeviceDatabase.class, CONNECTED_DB_NAME).build(); + btDeviceDatabase = Room.databaseBuilder(context, BTDeviceDatabase.class, DB_NAME).build(); + + mHandler = new Handler(Looper.getMainLooper()); + } + + public LiveData> getDescConnectedDevices() { + return connectedBTDeviceDatabase.connectedBTDeviceDao().getDescConnectedDevices(); + } + + public LiveData> getConnectedDevices() { + return connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDevices(); + } + + + public List getConnectedDevicesSync() { + return connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDevicesSync(); + } + + public ConnectedBTDevice getConnectedDeviceByAddressSync(String deviceAddress) { + return connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDeviceByAddress(deviceAddress); + } + + public void setConnectedDeviceToPrimary(String deviceAddress) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + Log.i(TAG, "setConnectedDeviceToPrimary: " + deviceAddress); + ConnectedBTDevice previousRecord = + connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDeviceByAddress(deviceAddress); + if (previousRecord != null) { + connectedBTDeviceDatabase.connectedBTDeviceDao().deleteConnectedBTDevice(previousRecord); + ConnectedBTDevice connectedBTDevice = new ConnectedBTDevice(); + connectedBTDevice.setDeviceAddress(previousRecord.getDeviceAddress()); + connectedBTDevice.setDeviceName(previousRecord.getDeviceName()); + connectedBTDevice.setContactsUploadPermission(previousRecord.getContactsUploadPermission()); + Log.i(TAG, "Inserting bt connected device entry: " + connectedBTDevice.getDeviceAddress()); + connectedBTDeviceDatabase.connectedBTDeviceDao().insertConnectedBTDevice(connectedBTDevice); + EventBus.getDefault().post(new PrimaryPhoneChangeMessage(connectedBTDevice, false)); + } + return null; + } + }.execute(); + } + + public void insertEntry(final BTDevice device) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + boolean isNewDevice = true; + if (connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDeviceByAddress( + device.getDeviceAddress()) + != null) { + ConnectedBTDevice previousRecord = + connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDeviceByAddress( + device.getDeviceAddress()); + connectedBTDeviceDatabase.connectedBTDeviceDao().deleteConnectedBTDevice(previousRecord); + Log.i(TAG, "Deleting previous bt record: " + device.getDeviceAddress()); + isNewDevice = false; + } + + BTDevice btDevice = btDeviceDatabase.btDeviceDao().getBTDeviceByAddressSync(device.getDeviceAddress()); + + ConnectedBTDevice connectedBTDevice = new ConnectedBTDevice(); + connectedBTDevice.setDeviceAddress(btDevice.getDeviceAddress()); + connectedBTDevice.setDeviceName(btDevice.getDeviceName()); + connectedBTDevice.setContactsUploadPermission(btDevice.getContactsUploadPermission()); + Log.i(TAG, "Inserting bt connected device entry: " + connectedBTDevice.getDeviceAddress()); + connectedBTDeviceDatabase.connectedBTDeviceDao().insertConnectedBTDevice(connectedBTDevice); + EventBus.getDefault().post(new PrimaryPhoneChangeMessage(connectedBTDevice, isNewDevice)); + return null; + } + }.execute(); + } + + public void deleteEntry(final ConnectedBTDevice entry) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + connectedBTDeviceDatabase.connectedBTDeviceDao().deleteConnectedBTDevice(entry); + List listData = getConnectedDevicesSync(); + if (listData != null && listData.size() > 0) { + int index = listData.size() - 1; + EventBus.getDefault().post(new PrimaryPhoneChangeMessage(listData.get(index), false)); + } else { + EventBus.getDefault().post(new PrimaryPhoneChangeMessage(null, false)); + } + return null; + } + }.execute(); + } + + public void updateContactsPermission(final String deviceAddress, final String permission) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + ConnectedBTDevice device = + connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDeviceByAddress(deviceAddress); + device.setContactsUploadPermission(permission); + connectedBTDeviceDatabase.connectedBTDeviceDao().updateConnectedBTDevice(device); + return null; + } + }.execute(); + } + + public void findConnectedBTDeviceEntry(BTDevice entry) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + ConnectedBTDevice targetDevice = + connectedBTDeviceDatabase.connectedBTDeviceDao().getConnectedDeviceByAddress( + entry.getDeviceAddress()); + mHandler.post(new Runnable() { + @Override + public void run() { + if (targetDevice != null) { + EventBus.getDefault().post(new ConnectedBTDeviceDiscoveryMessage(targetDevice, true)); + } else { + EventBus.getDefault().post(new ConnectedBTDeviceDiscoveryMessage(null, false)); + } + } + }); + return null; + } + }.execute(); + } + + /** + * Connected Bluetooth Device Discovery Message + */ + public static class ConnectedBTDeviceDiscoveryMessage { + private ConnectedBTDevice device; + private boolean isFound; + + public ConnectedBTDeviceDiscoveryMessage(ConnectedBTDevice device, boolean isFound) { + this.device = device; + this.isFound = isFound; + } + + public ConnectedBTDevice getBConnectedBTDevice() { + return this.device; + } + + public Boolean isFound() { + return this.isFound; + } + } + + /** + * Primary Phone Change Discovery Message + */ + public static class PrimaryPhoneChangeMessage { + private ConnectedBTDevice device; + private boolean isNewDevice; + public PrimaryPhoneChangeMessage(ConnectedBTDevice device, boolean newDevice) { + this.isNewDevice = newDevice; + this.device = device; + } + public ConnectedBTDevice getConnectedBTDevice() { + return this.device; + } + public boolean getIsNewDevice() {return this.isNewDevice;} + } +} diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/AndroidModule.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/AndroidModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/AndroidModule.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/AndroidModule.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationComponent.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationComponent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationComponent.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationComponent.java diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationModule.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationModule.java new file mode 100644 index 000000000..d9e890585 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/dependencies/CommunicationModule.java @@ -0,0 +1,31 @@ +package com.amazon.alexa.auto.comms.ui.dependencies; + +import android.content.Context; +import android.telecom.TelecomManager; + +import com.amazon.alexa.auto.comms.ui.handler.BluetoothDirectiveHandler; + +import java.lang.ref.WeakReference; + +import javax.inject.Singleton; + +import dagger.Module; +import dagger.Provides; + +/** + * Module to provide objects for Alexa communication. + */ +@Module +public class CommunicationModule { + @Provides + @Singleton + public BluetoothDirectiveHandler provideCommunicationDirectiveHandler(WeakReference context) { + return new BluetoothDirectiveHandler(context); + } + + @Provides + @Singleton + public TelecomManager provideTelecomManager(WeakReference context) { + return (TelecomManager) context.get().getSystemService(Context.TELECOM_SERVICE); + } +} diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationFragment.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationFragment.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationFragment.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationPreferenceFragment.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationPreferenceFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationPreferenceFragment.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/settings/CommunicationPreferenceFragment.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java similarity index 96% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java index 35f8633f8..8b616f53b 100644 --- a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragment.java @@ -89,7 +89,7 @@ private void observePrimaryConnectedDevice() { Log.d(TAG, "Primary device is found."); observeContactUploadPermission(deviceAddress); } else { - Log.d(TAG, "There is no connected device found."); + Log.i(TAG, "There is no connected device found."); } }); } @@ -121,6 +121,8 @@ private void observeContactUploadPermission(String deviceAddress) { // Update text content format = getResources().getString(R.string.contacts_permission_consent_body_with_alexa_custom_assistant); getYesButtonText.setText(R.string.contacts_consent_yes_with_alexa_custom_assistant); + TextView alexaContactsHint = fragmentView.findViewById(R.id.alexa_contacts_hint1); + alexaContactsHint.setVisibility(View.GONE); } else { format = getResources().getString(R.string.contacts_permission_consent_body); } diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModel.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModel.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModel.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModel.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java similarity index 91% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java index 0cd9f26a6..930982ed9 100644 --- a/platforms/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandler.java @@ -66,4 +66,10 @@ public void handleBTConnectionCommand(@NonNull BTDevice device, String connected mConnectedBTDeviceRepository.findConnectedBTDeviceEntry(device); } } + + public void handlePrimaryPhoneChangedCommand(String deviceAddress) { + if (deviceAddress != null && !deviceAddress.isEmpty()) { + mConnectedBTDeviceRepository.setConnectedDeviceToPrimary(deviceAddress); + } + } } diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiver.java b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiver.java new file mode 100644 index 000000000..564f8d2e4 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiver.java @@ -0,0 +1,86 @@ +package com.amazon.alexa.auto.comms.ui.receiver; + +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; + +import com.amazon.alexa.auto.comms.ui.Constants; +import com.amazon.alexa.auto.comms.ui.db.BTDevice; +import com.amazon.alexa.auto.comms.ui.dependencies.AndroidModule; +import com.amazon.alexa.auto.comms.ui.dependencies.DaggerCommunicationComponent; +import com.amazon.alexa.auto.comms.ui.handler.BluetoothDirectiveHandler; + +import javax.inject.Inject; + +import static com.amazon.alexa.auto.comms.ui.Constants.AACS_BT_CONNECTION_CHECK_COMPLETED; +import static com.amazon.alexa.auto.comms.ui.Constants.ALEXA_AUTO_COMMS_PRIMARY_PHONE_CHANGED; + +/** + * Receiver that gets Android telephony bluetooth directives. + */ +public class BluetoothReceiver extends BroadcastReceiver { + private static final String TAG = BluetoothReceiver.class.getSimpleName(); + + @VisibleForTesting + BTDevice mBTDevice = new BTDevice(); + + @Inject + BluetoothDirectiveHandler mBluetoothDirectiveHandler; + + @Inject + TelecomManager mTelecomManager; + + @Override + public void onReceive(Context context, Intent intent) { + if (mBluetoothDirectiveHandler == null) { + Log.i(TAG, this + " | first onReceive so doing injection"); + DaggerCommunicationComponent.builder() + .androidModule(new AndroidModule(context)) + .build() + .injectBluetoothReceiver(this); + } + + Log.d(TAG, "onReceive: " + intent.getAction()); + if ( intent.getAction() != null && (intent.getAction().equals(AACS_BT_CONNECTION_CHECK_COMPLETED) + || intent.getAction().equals(ALEXA_AUTO_COMMS_PRIMARY_PHONE_CHANGED))) { + mBluetoothDirectiveHandler.handlePrimaryPhoneChangedCommand(getPrimaryDevice()); + return; + } + + if (intent.getAction() != null && intent.getExtras() != null) { + mBTDevice.setDeviceAddress(intent.getExtras().getString(Constants.AACS_BT_DEVICE_ADDRESS, "")); + mBTDevice.setDeviceName(intent.getExtras().getString(Constants.AACS_BT_DEVICE_NAME, "")); + + String connectionState; + if (intent.getAction().equals(Constants.AACS_BT_CONNECTED)) { + connectionState = Constants.BT_CONNECTED; + } else { + connectionState = Constants.BT_DISCONNECTED; + } + + mBluetoothDirectiveHandler.handleBTConnectionCommand(mBTDevice, connectionState); + } + } + + public String getPrimaryDevice() { + String deviceAddress = ""; + if (mTelecomManager != null) { + PhoneAccountHandle handle = mTelecomManager.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL); + if (handle != null) { + deviceAddress = handle.getId(); + } + } + if (deviceAddress.isEmpty() || !BluetoothAdapter.checkBluetoothAddress(deviceAddress)) { + Log.e(TAG, "cannot find any valid primary device."); + return null; + } + return deviceAddress; + } +} diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/drawable/ic_arrow_right.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/drawable/ic_arrow_right.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/drawable/ic_arrow_right.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/drawable/ic_arrow_right.xml diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout-land/communication_setup_fragment.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout-land/communication_setup_fragment.xml new file mode 100644 index 000000000..2576d8c89 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout-land/communication_setup_fragment.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_consent_layout.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_consent_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_consent_layout.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_consent_layout.xml diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_pair_new_layout.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_pair_new_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_pair_new_layout.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_pair_new_layout.xml diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_preference_layout.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_preference_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_preference_layout.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_preference_layout.xml diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_settings_fragment.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_settings_fragment.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_settings_fragment.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_settings_fragment.xml diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_setup_fragment.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_setup_fragment.xml new file mode 100644 index 000000000..2576d8c89 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/layout/communication_setup_fragment.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/navigation/communication_navigation.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/navigation/communication_navigation.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/navigation/communication_navigation.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/navigation/communication_navigation.xml diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-de/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-de/strings.xml new file mode 100644 index 000000000..c3af2a0f7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-de/strings.xml @@ -0,0 +1,21 @@ + + + Rufen Sie Ihre Kontakte mit Alexa an + Sprachanrufe einrichten + Das Hochladen von Kontakten auf %1$s auf den Amazon-Dienst zulassen. + Rufen Sie mit [Acme Brandon] und Amazon Alexa Ihre Telefonkontakte per Sprachbefehl an. Ihre Kontakte auf %1$s werden auf den Amazon-Dienst hochgeladen. + Kontakte + Damit Kontakte mit Alexa angerufen werden können, werden die Kontakte auf diesem Telefon auf den Amazon-Dienst hochgeladen. + Laden Sie Ihre Kontakte auf den Amazon-Dienst hoch, um Sie über Ihren Namen anzurufen und Ihnen Nachrichten zu schicken + AKTIVIEREN + Kontakte verwenden + ÜBERSPRINGEN + Kontakte %1$s + aktiviert + deaktiviert + „Alexa, ruf Stefan an.“ + SMS + Zum Senden und Empfangen von SMS mit Alexa werden die SMS auf diesem Telefon auf den Amazon-Dienst hochgeladen. + SMS auf den Amazon-Dienst hochladen, damit sie Ihnen vorgelesen werden können + Neu koppeln + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rAU/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 000000000..41f889fa5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,21 @@ + + + Call your contacts with Alexa + Set up voice calling + Allow contacts on %1$s to be uploaded to the Amazon service. + Call your phone contacts hands free with [Acme Brandon] and Amazon Alexa. Your contacts on %1$s will be uploaded to the Amazon service. + Contacts + To enable calling contacts with Alexa, contacts on this phone will be uploaded to the Amazon service. + Upload contacts to the Amazon service to call \& message them by name + ENABLE + Use contacts + SKIP + Contacts %1$s + enabled + disabled + \"Alexa, call Sam\" + SMS messages + To enable SMS messaging with Alexa, SMS messages on this phone will be uploaded to the Amazon cloud. + Upload SMS messages to the Amazon service to have them read to you + Pair new + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rCA/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rCA/strings.xml new file mode 100644 index 000000000..41f889fa5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rCA/strings.xml @@ -0,0 +1,21 @@ + + + Call your contacts with Alexa + Set up voice calling + Allow contacts on %1$s to be uploaded to the Amazon service. + Call your phone contacts hands free with [Acme Brandon] and Amazon Alexa. Your contacts on %1$s will be uploaded to the Amazon service. + Contacts + To enable calling contacts with Alexa, contacts on this phone will be uploaded to the Amazon service. + Upload contacts to the Amazon service to call \& message them by name + ENABLE + Use contacts + SKIP + Contacts %1$s + enabled + disabled + \"Alexa, call Sam\" + SMS messages + To enable SMS messaging with Alexa, SMS messages on this phone will be uploaded to the Amazon cloud. + Upload SMS messages to the Amazon service to have them read to you + Pair new + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rIN/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 000000000..41f889fa5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,21 @@ + + + Call your contacts with Alexa + Set up voice calling + Allow contacts on %1$s to be uploaded to the Amazon service. + Call your phone contacts hands free with [Acme Brandon] and Amazon Alexa. Your contacts on %1$s will be uploaded to the Amazon service. + Contacts + To enable calling contacts with Alexa, contacts on this phone will be uploaded to the Amazon service. + Upload contacts to the Amazon service to call \& message them by name + ENABLE + Use contacts + SKIP + Contacts %1$s + enabled + disabled + \"Alexa, call Sam\" + SMS messages + To enable SMS messaging with Alexa, SMS messages on this phone will be uploaded to the Amazon cloud. + Upload SMS messages to the Amazon service to have them read to you + Pair new + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rUS/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 000000000..ba57b0042 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,21 @@ + + + Call your contacts with Alexa + Set up voice calling + Allow contacts on %1$s to be uploaded to the Amazon service. + Call your phone contacts hands-free with [Acme Brandon] and Amazon Alexa. Your contacts on %1$s will be uploaded to the Amazon service. + Contacts + To enable calling contacts with Alexa, contacts on this phone will be uploaded to the Amazon service. + Upload contacts to the Amazon service to call \& message them by name + ENABLE + Use contacts + SKIP + Contacts %1$s + enabled + disabled + \"Alexa, call Sam\" + SMS messages + To enable SMS messaging with Alexa, SMS messages on this phone wil be uploaded to the Amazon cloud. + Upload SMS messages to the Amazon service to have them read to you + Pair new + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en/strings.xml new file mode 100644 index 000000000..41f889fa5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-en/strings.xml @@ -0,0 +1,21 @@ + + + Call your contacts with Alexa + Set up voice calling + Allow contacts on %1$s to be uploaded to the Amazon service. + Call your phone contacts hands free with [Acme Brandon] and Amazon Alexa. Your contacts on %1$s will be uploaded to the Amazon service. + Contacts + To enable calling contacts with Alexa, contacts on this phone will be uploaded to the Amazon service. + Upload contacts to the Amazon service to call \& message them by name + ENABLE + Use contacts + SKIP + Contacts %1$s + enabled + disabled + \"Alexa, call Sam\" + SMS messages + To enable SMS messaging with Alexa, SMS messages on this phone will be uploaded to the Amazon cloud. + Upload SMS messages to the Amazon service to have them read to you + Pair new + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rMX/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 000000000..457c68605 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,21 @@ + + + Llamar a tus contactos con Alexa + Configurar llamadas de voz + Permite que los contactos que tienes en %1$s se carguen al servicio de Amazon. + Llama a los contactos de tu teléfono a manos libres con [Acme Brandon] y Amazon Alexa. Los contactos que tienes en %1$s se cargarán al servicio de Amazon. + Contactos + Para activar las llamadas a contactos con Alexa, los contactos de este teléfono se cargarán al servicio de Amazon. + Carga los contactos al servicio de Amazon para llamarlos y enviarles mensajes usando su nombre + ACTIVAR + Usar contactos + OMITIR + Permiso de contactos %1$s + activado + desactivado + “Alexa, llama a Samuel” + Mensajes SMS + Para activar los mensajes SMS con Alexa, los mensajes SMS de este teléfono se cargarán a la nube de Amazon. + Carga los mensajes SMS al servicio de Amazon para escucharlos + Vincular otro + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rUS/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..457c68605 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,21 @@ + + + Llamar a tus contactos con Alexa + Configurar llamadas de voz + Permite que los contactos que tienes en %1$s se carguen al servicio de Amazon. + Llama a los contactos de tu teléfono a manos libres con [Acme Brandon] y Amazon Alexa. Los contactos que tienes en %1$s se cargarán al servicio de Amazon. + Contactos + Para activar las llamadas a contactos con Alexa, los contactos de este teléfono se cargarán al servicio de Amazon. + Carga los contactos al servicio de Amazon para llamarlos y enviarles mensajes usando su nombre + ACTIVAR + Usar contactos + OMITIR + Permiso de contactos %1$s + activado + desactivado + “Alexa, llama a Samuel” + Mensajes SMS + Para activar los mensajes SMS con Alexa, los mensajes SMS de este teléfono se cargarán a la nube de Amazon. + Carga los mensajes SMS al servicio de Amazon para escucharlos + Vincular otro + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..ae68ee6a6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-es/strings.xml @@ -0,0 +1,21 @@ + + + Llamar a tus contactos con Alexa + Configurar llamadas de voz + Permite que tus contactos de %1$s se carguen periódicamente al servicio de Amazon. + Llama a los contactos de tu teléfono con [Acme Brandon] y Amazon Alexa. Tus contactos de %1$s se cargarán al servicio de Amazon. + Contactos + Para activar las llamadas con Alexa a contactos, se cargarán los contactos de este teléfono en el servicio de Amazon. + Cargar contactos al servicio de Amazon para llamarles y mandarles mensajes usando su nombre + ACTIVAR + Usar contactos + OMITIR + Contactos de %1$s + activado + desactivado + \"Alexa, llama a Amparo\" + Mensajes SMS + Para activar los mensajes SMS con Alexa, se cargarán los mensajes SMS de este teléfono en el Cloud de Amazon. + Carga los mensajes SMS en el servicio de Amazon para que te los lea + Vincular nuevo + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr-rCA/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000..235beb9dd --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,21 @@ + + + Appelez vos contacts avec Alexa + Configurer les appels vocaux + Autoriser le téléversement des contacts sur %1$s vers le service Amazon. + Appelez les contacts de votre téléphone mains libres avec [Acme Brandon] et Amazon Alexa. Vos contacts sur %1$s seront téléversés vers le service Amazon. + Contacts + Pour permettre d\'appeler des contacts avec Alexa, les contacts sur ce téléphone seront téléversés vers le service Amazon. + Téléversez les contacts vers le service Amazon pour les appeler et leur envoyer un message par leur nom + ACTIVER + Utiliser les contacts + IGNORER + Contacts %1$s + activé + désactivé + « Alexa, appelle Sam. » + Messages texte + Pour activer les messages texte avec Alexa, les messages texte sur ce téléphone seront téléversés vers le nuage Amazon. + Téléversez les messages texte vers le service Amazon pour qu\'on vous les lise + Nouveau jumelage + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr/strings.xml new file mode 100644 index 000000000..efc858621 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-fr/strings.xml @@ -0,0 +1,21 @@ + + + Appeler vos contacts avec Alexa + Configurer les appels vocaux + Autorisez le téléchargement sur le service Amazon des contacts sur %1$s. + Appelez vos contacts en mode mains-libres avec [Acme Brandon] et Amazon Alexa. Vos contacts sur %1$s seront téléchargés sur le service Amazon. + Contacts + Pour activer les appels des contacts avec Alexa, les contacts de ce téléphone seront téléchargés sur le service Amazon. + Téléchargez des contacts sur le service Amazon afin de pouvoir les appeler et leur envoyer des messages en utilisant leur nom + ACTIVER + Utiliser les contacts + IGNORER + Contacts %1$s + activé + désactivé + « Alexa, appelle Sam. » + Messages SMS + Pour activer les messages SMS avec Alexa, les messages SMS sur ce téléphone seront téléchargés sur le Cloud Amazon. + Téléchargez les messages SMS sur le service Amazon pour qu\'ils vous soient lus + Jumeler un nouvel appareil + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-hi-rIN/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-hi-rIN/strings.xml new file mode 100644 index 000000000..ece34ab6b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-hi-rIN/strings.xml @@ -0,0 +1,21 @@ + + + Alexa के ज़रिए अपने कॉन्टैक्ट में शामिल लोगों को कॉल करें + वॉइस कॉलिंग सेट अप करें + %1$s पर मौजूद कॉन्टैक्ट को Amazon सेवा पर अपलोड करने की अनुमति दें. + [Acme Brandon] और Amazon Alexa के साथ अपने फ़ोन में मौजूद कॉन्टैक्ट को हैंड्स-फ़्री कॉलिंग करें. %1$s पर मौजूद आपके कॉन्टैक्ट को Amazon सेवा पर अपलोड किया जाएगा. + कॉन्टैक्ट + Alexa के ज़रिए कॉन्टैक्ट के साथ कॉलिंग चालू करने के लिए, इस फ़ोन पर मौजूद कॉन्टैक्ट को Amazon सेवा पर अपलोड किया जाएगा. + उन्हें नाम से कॉल और मैसेज करने के लिए Amazon सेवा पर कॉन्टैक्ट अपलोड करें + चालू करें + कॉन्टैक्ट का इस्तेमाल करें + छोड़ें + कॉन्टैक्ट %1$s + चालू है + बंद है + \"Alexa, सैम को कॉल करो\" + SMS मैसेज + Alexa के साथ SMS मैसेजिंग चालू करने के लिए, इस फ़ोन पर मौजूद SMS मैसेज Amazon क्लाउड पर अपलोड किए जाएंगे. + SMS मैसेज को Amazon सेवा में अपलोड करें ताकि आपको उन्हें पढ़कर सुनाया जा सके + नया डिवाइस पेयर करें + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-it/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-it/strings.xml new file mode 100644 index 000000000..a9b9e480c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-it/strings.xml @@ -0,0 +1,21 @@ + + + Chiama i tuoi contatti con Alexa + Configura le chiamate vocali + Autorizza il caricamento dei contatti su %1$s nel servizio Amazon. + Chiama i tuoi contatti senza l\'utilizzo delle mani con [Acme Brandon] e Amazon Alexa. I tuoi contatti su %1$s saranno caricato nel servizio Amazon. + Contatti + Per attivare le chiamate verso i contatti con Alexa, i contatti di questo telefono saranno caricati sul servizio Amazon. + Carica i contatti nel servizio Amazon per poterli chiamare e mandargli messaggi, usando il loro nome. + ATTIVA + Usa contatti + SALTA + Contatti %1$s + attivato + non attivo + \"Alexa, chiama Luca\" + Messaggi SMS + Per attivare i messaggi SMS con Alexa, gli SMS di questo telefono saranno caricati sul servizio Amazon. + Carica i messaggi SMS sul servizio Amazon per farteli leggere + Associa nuovo + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-ja/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-ja/strings.xml new file mode 100644 index 000000000..5616045ad --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-ja/strings.xml @@ -0,0 +1,21 @@ + + + 連絡先とAlexaで通話 + 音声通話をセットアップ + %1$sの連絡先をAmazonのサービスにアップロードすることを許可します。 + [Acme Brandon]で、スマートフォンの連絡先にハンズフリーで通話を開始できます。%1$sの連絡先がAmazonのサービスにアップロードされます。 + 連絡先 + Alexaによる通話機能をオンにすると、このスマートフォンの連絡先がAmazonサービスにアップロードされます。 + Amazonのサービスに連絡先をアップロードすると、名前を言うだけで通話・メッセージ送信ができるようになります + オンにする + 連絡先を使用 + スキップ + 連絡先%1$s + がオンになりました + がオフになりました + 「アレクサ、お母さんにかけて」 + SMSメッセージ + AlexaによるSMSメッセージ送信機能をオンにすると、このスマートフォンのSMSメッセージがAmazonのクラウドにアップロードされます。 + SMSメッセージの読み上げ機能を使うには、メッセージをAmazonサービスにアップロードする必要があります。 + 新しいデバイスをペアリング + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-land/dimens.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-land/dimens.xml new file mode 100644 index 000000000..4788fdcc5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-land/dimens.xml @@ -0,0 +1,24 @@ + + + + 150dp + 108dp + 8dp + 32dp + 35dp + 100dp + 100dp + 20sp + + 8dp + 50dp + 50dp + 32dp + + + 64dp + 64dp + 122dp + 32dp + 8dp + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-pt-rBR/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000..01ff588a6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,21 @@ + + + Faça chamadas para seus contatos com a Alexa + Configurar chamadas de voz + Permitir que contatos no %1$s sejam carregados no serviço da Amazon. + Faça chamadas sem usar as mãos para os contatos do seu telefone com o [Acme Brandon] e o Amazon Alexa. Seus contatos no %1$s serão carregados no serviço da Amazon. + Contatos + Para ativar chamadas para os contatos com a Alexa, os contatos neste telefone serão carregados no serviço da Amazon. + Carregue os contatos no serviço da Amazon para fazer chamadas e enviar mensagem para eles por nome + ATIVAR + Usar contatos + PULAR + Contatos %1$s + ativado + desativado + \"Alexa, ligue para o Sam\" + Mensagens SMS + Para ativar mensagens SMS com a Alexa, as mensagens SMS neste telefone serão carregadas na nuvem da Amazon. + Carregue as mensagens SMS no serviço da Amazon para que elas sejam lidas para você + Parear novo + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/dimens.xml new file mode 100644 index 000000000..b93e0ddad --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/dimens.xml @@ -0,0 +1,28 @@ + + + + 150dp + 108dp + 50dp + 32dp + 220dp + 50dp + 100dp + 100dp + 20sp + + 8dp + 50dp + 32dp + 50dp + 32dp + + + 64dp + 64dp + 122dp + 32dp + 8dp + 0dp + 1dp + diff --git a/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/strings.xml new file mode 100644 index 000000000..ba57b0042 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/values/strings.xml @@ -0,0 +1,21 @@ + + + Call your contacts with Alexa + Set up voice calling + Allow contacts on %1$s to be uploaded to the Amazon service. + Call your phone contacts hands-free with [Acme Brandon] and Amazon Alexa. Your contacts on %1$s will be uploaded to the Amazon service. + Contacts + To enable calling contacts with Alexa, contacts on this phone will be uploaded to the Amazon service. + Upload contacts to the Amazon service to call \& message them by name + ENABLE + Use contacts + SKIP + Contacts %1$s + enabled + disabled + \"Alexa, call Sam\" + SMS messages + To enable SMS messaging with Alexa, SMS messages on this phone wil be uploaded to the Amazon cloud. + Upload SMS messages to the Amazon service to have them read to you + Pair new + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/main/res/xml/communication_preferences.xml b/aacs/android/app-components/alexa-auto-comms-ui/src/main/res/xml/communication_preferences.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/main/res/xml/communication_preferences.xml rename to aacs/android/app-components/alexa-auto-comms-ui/src/main/res/xml/communication_preferences.xml diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragmentTest.java b/aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragmentTest.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModelTest.java b/aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModelTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModelTest.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/fragment/setup/CommunicationConsentViewModelTest.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandlerTest.java b/aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandlerTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandlerTest.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/handler/BluetoothDirectiveHandlerTest.java diff --git a/platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiverTest.java b/aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiverTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiverTest.java rename to aacs/android/app-components/alexa-auto-comms-ui/src/test/java/com/amazon/alexa/auto/comms/ui/receiver/BluetoothReceiverTest.java diff --git a/aacs/android/app-components/alexa-auto-contacts/README.md b/aacs/android/app-components/alexa-auto-contacts/README.md new file mode 100644 index 000000000..8d1a4d5c7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-contacts/README.md @@ -0,0 +1,146 @@ +# AACS Contacts +The AACS Contacts library is an Android library used by the AACS Core Service to fetch contact information from the vehicle's head unit and send it to Alexa. The AACS Core Service can also use this library to remove from Alexa the uploaded contact information. + + +## Table of Contents +- [Overview](#overview) +- [Building the Library](#building-the-library) +- [Setup for AACS Contacts Library](#setup-for-aacs-contacts-library) +- [Sequence Diagrams](#sequence-diagrams) +- [How the AACS Contacts Library Works with an Address Book](#how-the-aacs-contacts-library-works-with-an-address-book) + +## Overview +Using the Contacts Library, AACS enables your app to interact with the Auto SDK Engine easily to add or remove an address book, which contains all contact information maintained by the Android Contacts Provider. For information about Contacts Provider, see the [Contact Provider documentation](https://developer.android.com/guide/topics/providers/contacts-provider). + +>**Note:** An address book can be of the type Contact or Navigation. The Contacts Library only works with the Contact type. For example, AACS cannot use the library to fetch data about a navigation favorite. See the [Address Book Module README](../../../../modules/address-book/README.md) for more information about the `AddressBookType` API. + +The following list describes the major components of the library: + +* The AACS Contacts Service is responsible for: + * Receiving AASB `AddAddressBook` or `RemoveAddressBook` messages from the AACS Core Service. + * Receiving defined intents from your application to upload or remove an address book + +* The AACS Contacts Library platform implementation (`PhoneBookController`) is responsible for: + * Fetching the address book from the Android Contacts Provider + * Parsing all contact data from the address book into an AASB `AddAddressBook` message + * Sending the AASB `AddAddressBook` intent to the AACS Core Service to upload the address book to Alexa + * Sending the AASB `RemoveAddressBook` intent to the AACS Core Service to remove from Alexa an address book with a specific `addressBookSourceId`, a unique address book identifier defined in the Address Book handler (Bluetooth MAC address of connected phone) + * Providing the API for adding or removing an address book for your application to call + +The AACS Contacts Library is an optional module, which you can use as is or as a reference when you integrate the Address Book module with AACS. You can build it into an Android archive (AAR) to be included in the AACS APK (recommended) or in your application APK. + +## Building the Library +You can build the library locally using the following steps: + 1) Enter the following command to change the directory: + ~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app + ~~~ + 2) Enter the following command to build the Contacts library: + ~~~ + ./gradlew :alexa-auto-contacts:assembleRelease + ~~~ + Replace `assembleRelease` with `assembleDebug` if you want to build the debug version of the library. The generated AAR is available at `alexa-auto-sdk/aacs/android/app-components/alexa-auto-contacts/aacscontacts/build/outputs/aar`. + You must include the `AACSIPC`, `AACSConstants`, `AACSCommonUtils`, `AACS` and `Auto SDK` AARs in your application to use with the AACS Contacts AAR. + + +To enable contacts support in the AACS Sample App, follow these steps: +1) Enter the following command to change the directory: +~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app +~~~ +2) Enter the following command to start the local build with contacts enabled. +~~~ + ./gradlew assembleLocalRelease -PenabledContacts +~~~ +For more build options, see the [AACS Sample App README](../../sample-app/README.md#optional-arguments). + +## Setup for AACS Contacts Library +Before using the AACS Contacts Library, follow these major steps: + +1) Provide permission in your application's Android manifest. +2) Specify targets for intents from the AACS Core Service. + +### Providing Permission in Android Manifest +For security reasons, for your application to send intents to or receive intents from the AACS Contacts Service, specify the `com.amazon.aacscontacts` permission in your application's Android manifest as follows: + +``` + +``` + +### Specifying Intent Targets +The AACS Contacts Service listens to intents from the AACS Core Service with the `AddressBook` topic. To specify AACS Contacts Service with an intent target for the `AddressBook` topic, follow one of these steps: + +* Manually specify the messages in the AACS configuration file, as described in the [AACS README](../../README.md#specifying-the-intent-targets-for-handling-messages). The targets in the AACS configuration file override the ones specified by intent filters. The following example shows how to specify an intent target in the AACS configuration file. In this example, the AACS Contacts Library AAR is part of the AACS APK. + +``` + "AddressBook" : { + "type": ["", "SERVICE", ...], + "package": ["", "com.amazon.alexaautoclientservice", ...], + "class": ["", "com.amazon.aacscontacts.AACSContactsService", ...] + } +``` + +* Omit ANY targets for `AddressBook` in the AACS configuration file. As a result, the intent filter defined in the AACS Contacts Library takes effect, enabling the AACS Contacts Service to receive the intents. + +## Sequence Diagrams +The following diagram illustrates the flow when an address book is uploaded to Alexa. +

+ +

+ +The following diagram illustrates the flow when an address book is removed from Alexa. +

+ +

+ +## How the AACS Contacts Library Works with an Address Book +This section describes how the Contacts Library uploads or removes an address book. + +### Uploading Address Book +Use one of the following methods to upload an address book to Alexa: + +* Use intent. Your application can inform the AACS Contacts Library to upload an address book to Alexa by using an intent. When the AACS Contacts Library receives the intent, the library fetches contacts from the Contacts Provider on the head unit and uploads them to Alexa. To determine whether the upload is successful, your application can subscribe to the AASB `AddressBook` intents. Define the attributes of the intent as follows: + + * Action is `com.amazon.aacscontacts.upload`. + * Category is `com.amazon.aacscontacts`. + * Extras is `addressBookSourceId` (Must be Bluetooth MAC address from connected phone fetched from client application) and the name of the address book (defined in the Address Book platform interface), specified as follows: + +~~~ + { + "addressBookSourceId": "", + "addressBookName": "" + } +~~~ + +* Use a direct API call. This method is applicable only if you put the AACS Contacts Library in your application. The `PhoneBookController.uploadContacts` API blocks the current thread and returns a boolean value indicating if the operation is successful. The following code shows how to use `PhoneBookController.uploadContacts`: + +``` + // Instantiate PhoneBookController + PhoneBookController phoneBookController = new PhoneBookController(context); + Boolean succeeded = phoneBookController.uploadContacts(addressBookSourceId, addressBookName); +``` +Note that `addressBookSourceId` must be Bluetooth MAC address from connected phone fetched from client application in order to have contacts upload working properly + +### Removing Address Book +Use one of the following methods to remove an address book from Alexa: + +* Use intent. Your application can inform the AACS Contacts Service to remove an address book from Alexa by using an intent. Define the attributes of the intent as follows: + +* Action is `com.amazon.aacscontacts.remove`. +* Category is `com.amazon.aacscontacts`. +* Extras is `addressBookSourceId` (defined in the Address Book platform interface), specified as follows: + +``` + { + "addressBookSourceId": "" + } +``` + +* Use a direct API call. This method is applicable only if you put the AACS Contacts Library in your application. The `PhoneBookController.removeContacts` API blocks the current thread and returns a boolean value indicating if the operation is successful. The following code shows how to use `PhoneBookController.removeContacts`: + +``` + // Instantiate PhoneBookController + PhoneBookController phoneBookController = new PhoneBookController(context); + Boolean succeeded = phoneBookController.removeContacts(addressBookSourceId); +``` +Note that `addressBookSourceId` must be Bluetooth MAC address from connected phone fetched from client application in order to have contacts remove working properly \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-media-player/.gitignore b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/.gitignore rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/.gitignore diff --git a/aacs/android/app-components/alexa-auto-contacts/aacscontacts/build.gradle b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/build.gradle new file mode 100644 index 000000000..8ce740d56 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/build.gradle @@ -0,0 +1,50 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 27 + versionCode 1 + versionName "4.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests.returnDefaultValues = true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.aar']) + implementation project(':aacsconstants') + implementation project(':aacscommonutils') + implementation project(':aacsipc') + + implementation 'androidx.appcompat:appcompat:1.2.0' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test:runner:1.1.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + testImplementation 'org.mockito:mockito-core:1.10.19' + testImplementation 'org.powermock:powermock-api-mockito:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4:1.6.2' + androidTestImplementation 'org.mockito:mockito-android:2.22.0' +} diff --git a/extensions/bluetooth/aacs/android/modules/aacs-bluetooth/consumer-rules.pro b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/consumer-rules.pro similarity index 100% rename from extensions/bluetooth/aacs/android/modules/aacs-bluetooth/consumer-rules.pro rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/consumer-rules.pro diff --git a/platforms/android/app-components/alexa-auto-apl-renderer/proguard-rules.pro b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-apl-renderer/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/AACSContactsService.java b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/AACSContactsService.java similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/AACSContactsService.java rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/AACSContactsService.java diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/Constants.java b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/Constants.java similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/Constants.java rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/Constants.java diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/PhoneBookController.java b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/PhoneBookController.java similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/PhoneBookController.java rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/java/com/amazon/aacscontacts/PhoneBookController.java diff --git a/platforms/android/alexa-auto-client-service/android-service/service/src/main/res/drawable/alexa_notification_icon.png b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/drawable/alexa_notification_icon.png similarity index 100% rename from platforms/android/alexa-auto-client-service/android-service/service/src/main/res/drawable/alexa_notification_icon.png rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/drawable/alexa_notification_icon.png diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/test/java/com/amazon/aacscontacts/PhoneBookControllerTests.java b/aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/test/java/com/amazon/aacscontacts/PhoneBookControllerTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/src/test/java/com/amazon/aacscontacts/PhoneBookControllerTests.java rename to aacs/android/app-components/alexa-auto-contacts/aacscontacts/src/test/java/com/amazon/aacscontacts/PhoneBookControllerTests.java diff --git a/platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-add.png b/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-add.png similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-add.png rename to aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-add.png diff --git a/platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-add.puml b/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-add.puml similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-add.puml rename to aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-add.puml diff --git a/platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.png b/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.png similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.png rename to aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.png diff --git a/platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.puml b/aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.puml similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.puml rename to aacs/android/app-components/alexa-auto-contacts/assets/contactsLib-remove.puml diff --git a/aacs/android/app-components/alexa-auto-contacts/build.gradle b/aacs/android/app-components/alexa-auto-contacts/build.gradle new file mode 100644 index 000000000..936715602 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-contacts/build.gradle @@ -0,0 +1,45 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.versions = [ + 'kotlin': '1.4.0', + 'moshi': '1.9.3', + + // Test Dependencies + 'mockito': '3.4.0', + ] + + ext.deps = [ + 'kotlin_stdlib': "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}", + 'androidx_annotation': "androidx.annotation:annotation:1.1.0", + 'moshi': "com.squareup.moshi:moshi:${versions.moshi}", + 'moshi_codegen': "com.squareup.moshi:moshi-kotlin-codegen:${versions.moshi}", + + 'junit': 'junit:junit:4.12', + 'mockito': "org.mockito:mockito-core:${versions.mockito}", + 'roboelectric': 'org.robolectric:robolectric:4.3', + ] + + repositories { + google() + mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/platforms/android/alexa-auto-client-service/commonutils/gradle.properties b/aacs/android/app-components/alexa-auto-contacts/gradle.properties similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/gradle.properties rename to aacs/android/app-components/alexa-auto-contacts/gradle.properties diff --git a/aacs/android/app-components/alexa-auto-contacts/settings.gradle b/aacs/android/app-components/alexa-auto-contacts/settings.gradle new file mode 100644 index 000000000..196dacf31 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-contacts/settings.gradle @@ -0,0 +1,9 @@ +rootProject.name='alexa-auto-contacts' +include ':aacscontacts' +gradle.ext.aacsRoot = '../..' +include ':aacsconstants' +project(':aacsconstants').projectDir = new File(gradle.ext.aacsRoot, '/common/constants/aacsconstants') +include ':aacsipc' +project(':aacsipc').projectDir = new File(gradle.ext.aacsRoot, '/common/ipc/aacsipc') +include ':aacscommonutils' +project(':aacscommonutils').projectDir = new File(gradle.ext.aacsRoot, '/common/commonutils/aacscommonutils') diff --git a/platforms/android/app-components/alexa-auto-navigation/.gitignore b/aacs/android/app-components/alexa-auto-device-usage/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/.gitignore rename to aacs/android/app-components/alexa-auto-device-usage/.gitignore diff --git a/aacs/android/app-components/alexa-auto-device-usage/README.md b/aacs/android/app-components/alexa-auto-device-usage/README.md new file mode 100644 index 000000000..34c52e2fd --- /dev/null +++ b/aacs/android/app-components/alexa-auto-device-usage/README.md @@ -0,0 +1,38 @@ +# Alexa Auto Device Usage +Alexa Auto Device Usage library provides an implementation that enables the AACS Sample App to capture network usage data of Alexa Auto Client Service (AACS) using Android [NetworkStatsManager](https://developer.android.com/reference/android/app/usage/NetworkStatsManager). The data is logged as a metric and is sent to Amazon endpoints if AACS is built with the `Device Client Metrics (DCM)` extension. To obtain the pre-built AACS AAR with DCM extension, contact your Amazon Solutions Architect (SA) or Partner Manager for more information. + +## Overview +The library consists of the following components: +* `AASBReceiver`. This Android BroadcastReceiver subsribes to [AASB StartService message](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/aasb/aasb-docs/AASB/index.html#startservice) and [AASB StopService message](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/aasb/aasb-docs/AASB/index.html#stopservice) to get the current AACS running status, based on which the `DeviceUsageHandler` can start or stop the network data recording. +* `DeviceUsageHandler`. The handler is responsible for starting and stopping the `NetworkStatsManagerRunner` according to the AACS running status. It starts the `NetworkStatsManagerRunner` in an executor thread which queries the network usage every 5 minutes and publishes the data via [DeviceUsage `ReportNetworkDataUsageMessage` message](https://alexa.github.io/alexa-auto-sdk/docs/sdk-docs/modules/core/aasb-docs/DeviceUsage/index.html#reportnetworkdatausage) to the Auto SDK engine. +* `NetworkStatsManagerRunner`. This class captures the network usage data using `NetworkStatsManager` APIs and calls the `DeviceUsageHandler` to report the data. + +## Providing Permissions for Alexa Auto Device Usage Library +Using the Alexa Auto Device Usage Library requires the AACS sample app to hold certain Android permissions. + +* If the Android version of your device is lower than 10 (Android Q): The Alexa application needs the `android.permission.READ_PHONE_STATE` permission to access the `subscriber id` (associated to the eSIM of a user), which is required to query the network consumption over the `MOBILE` interface. You can grant this permission to AACS sample app in "Settings" -> "Apps & notifications" -> "Alexa" -> "Permissions" -> "Phone". + +* If the Android version of your device is 10 (Android Q) or higher: The Alexa application must be installed as a privileged system application and it must have the `android.permission.READ_PRIVILEGED_PHONE_STATE` privileged permission in order to be able to get the `subscriber id`. + +> **Note** The Alexa Auto Device Usage Library carries all the Android permissions (`READ_PHONE_STATE`, `READ_PRIVILEGED_PHONE_STATE` and `PACKAGE_USAGE_STATS`) your application needs in order to enable the network usage data recording. To use this library, make sure your AACS sample app is built with the `-PenabledDeviceUsage` option, as specified in the [Building AACS Sample App with Alexa Auto Device Usage Library](./README.md#building-aacs-sample-app-with-alexa-auto-device-usage-library) section. If your device is on Android 10 or higher version, install AACS sample app as a system privileged app, and place the following `privapp-permissions-com.amazon.alexa.auto.app.xml` file under the `/etc/permissions` directory on your device: + +```xml + + + + + + + +``` + +## Building AACS Sample App with Alexa Auto Device Usage Library +To build the AACS Sample App with Alexa Auto Device Usage library, go to `${AAC_SDK_HOME}/samples/android-aacs-sample-app/` and enter the following command: + +```shell +// release build +gradle assembleRelease -PenabledDeviceUsage + +// debug build +gradle assembleDebug -PenabledDeviceUsage +``` \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-device-usage/build.gradle b/aacs/android/app-components/alexa-auto-device-usage/build.gradle similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/build.gradle rename to aacs/android/app-components/alexa-auto-device-usage/build.gradle diff --git a/platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra/consumer-rules.pro b/aacs/android/app-components/alexa-auto-device-usage/consumer-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/android-service/modules/aacs-extra/consumer-rules.pro rename to aacs/android/app-components/alexa-auto-device-usage/consumer-rules.pro diff --git a/platforms/android/app-components/alexa-auto-apps-common-ui/proguard-rules.pro b/aacs/android/app-components/alexa-auto-device-usage/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-ui/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-device-usage/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-device-usage/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-device-usage/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-device-usage/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/AASBReceiver.java b/aacs/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/AASBReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/AASBReceiver.java rename to aacs/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/AASBReceiver.java diff --git a/platforms/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/DeviceUsageHandler.java b/aacs/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/DeviceUsageHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/DeviceUsageHandler.java rename to aacs/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/DeviceUsageHandler.java diff --git a/platforms/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/NetworkStatsManagerRunner.java b/aacs/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/NetworkStatsManagerRunner.java similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/NetworkStatsManagerRunner.java rename to aacs/android/app-components/alexa-auto-device-usage/src/main/java/com/amazon/alexa/auto/deviceusage/NetworkStatsManagerRunner.java diff --git a/platforms/android/app-components/alexa-auto-device-usage/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-device-usage/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-device-usage/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/.gitignore b/aacs/android/app-components/alexa-auto-lwa-auth/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/.gitignore rename to aacs/android/app-components/alexa-auto-lwa-auth/.gitignore diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/README.md b/aacs/android/app-components/alexa-auto-lwa-auth/README.md similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/README.md rename to aacs/android/app-components/alexa-auto-lwa-auth/README.md diff --git a/aacs/android/app-components/alexa-auto-lwa-auth/build.gradle b/aacs/android/app-components/alexa-auto-lwa-auth/build.gradle new file mode 100644 index 000000000..5ccf27deb --- /dev/null +++ b/aacs/android/app-components/alexa-auto-lwa-auth/build.gradle @@ -0,0 +1,62 @@ +apply plugin: 'com.android.library' +apply plugin: 'checkstyle' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 25 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-lwa-auth" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } +} + +dependencies { + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':aacscommonutils') + + implementation project(":alexa-auto-apis") + implementation project(':alexa-auto-apps-common-util') + + if(project.hasProperty('enabledPreviewMode')){ + implementation project(':alexa-auto-preview-mode-util') + } + + implementation deps.androidx_annotation + implementation deps.rxjava3 + implementation deps.eventbus + + implementation deps.androidx_security_crypto + implementation deps.androidx_identity_credential +} diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/proguard-rules.pro b/aacs/android/app-components/alexa-auto-lwa-auth/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-lwa-auth/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-lwa-auth/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/AndroidManifest.xml new file mode 100644 index 000000000..55691f02d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/AndroidManifest.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AlexaClientReceiver.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AlexaClientReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AlexaClientReceiver.java rename to aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AlexaClientReceiver.java diff --git a/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AuthReceiver.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AuthReceiver.java new file mode 100644 index 000000000..ff984f75c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/AuthReceiver.java @@ -0,0 +1,122 @@ +package com.amazon.alexa.auto.lwa; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.amazon.aacsconstants.Action; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; +import com.amazon.alexa.auto.apis.auth.AuthState; +import com.amazon.alexa.auto.apis.auth.AuthWorkflowData; + +import org.greenrobot.eventbus.EventBus; +import org.json.JSONException; +import org.json.JSONObject; + +public class AuthReceiver extends BroadcastReceiver { + private static final String TAG = AuthReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null || intent.getAction() == null) { + return; + } + + AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { + + try{ + JSONObject obj = new JSONObject(message.payload); + String service = obj.getString(LWAAuthConstants.AUTH_SERVICE); + + if(service.equals(LWAAuthConstants.AUTH_PROVIDER_SERVICE_NAME)) { + switch (message.action) { + case Action.Authorization.EVENT_RECEIVED: + handleAuthorizationEvent(obj); + break; + case Action.Authorization.GET_AUTHORIZATION_DATA: + EventBus.getDefault().post(new AuthWorkflowData( + AuthState.Auth_Provider_Authorization_Get_Data, null, message.messageId)); + break; + case Action.Authorization.AUTHORIZATION_STATE_CHANGED: + handleAuthorizationStateChanged(obj); + break; + case Action.Authorization.AUTHORIZATION_ERROR: + handleAuthorizationError(obj); + break; + } + } + } + catch (JSONException e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + }); + } + + private void handleAuthorizationEvent(JSONObject obj) { + + try{ + String event = obj.getString("event"); + + if (event.contains("requestAuthorization")) { + EventBus.getDefault().post( + new AuthWorkflowData(AuthState.Auth_Provider_Request_Authorization, null, null)); + } else if (event.contains("logout")) { + EventBus.getDefault().post(new AuthWorkflowData(AuthState.Auth_Provider_Logout, null, null)); + } + } catch (Exception e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + } + + private void handleAuthorizationStateChanged(JSONObject obj) { + + try{ + + String authState = obj.getString("state"); + + switch (authState) { + case "AUTHORIZED": + // It means we have successfully received and saved the auth token on the device side. + EventBus.getDefault().post(new AuthWorkflowData(AuthState.Auth_Provider_Token_Saved, null, null)); + break; + case "UNAUTHORIZED": + EventBus.getDefault().post( + new AuthWorkflowData(AuthState.Auth_Provider_Not_Authorized, null, null)); + break; + case "AUTHORIZING": + EventBus.getDefault().post(new AuthWorkflowData(AuthState.Auth_Provider_Authorizing, null, null)); + break; + } + }catch (Exception e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + } + private void handleAuthorizationError(JSONObject obj) { + + try{ + + String error = obj.getString("error"); + + switch (error) { + case "AUTH_FAILURE": + Log.w(TAG, "Auth token failure."); + EventBus.getDefault().post( + new AuthWorkflowData(AuthState.Auth_Provider_Authorization_Error, null, null)); + break; + case "UNKNOWN_ERROR": + Log.e(TAG, "Unknown error Authorization message="); + break; + case "START_AUTHORIZATION_FAILED": + Log.e(TAG, "Start Authorization Failed message"); + break; + case "LOGOUT_FAILED": + Log.e(TAG, "Logout Failed. message"); + break; + } + } catch (Exception e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/CBLAuthReceiver.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/CBLAuthReceiver.java new file mode 100644 index 000000000..f69219739 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/CBLAuthReceiver.java @@ -0,0 +1,214 @@ +package com.amazon.alexa.auto.lwa; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.amazon.aacsconstants.AACSConstants; +import com.amazon.aacsconstants.Topic; +import com.amazon.aacsipc.AACSSender; +import com.amazon.aacsipc.IPCConstants; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; + +import com.amazon.aacsconstants.Action; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; +import com.amazon.alexa.auto.apis.auth.AuthState; +import com.amazon.alexa.auto.apis.auth.AuthWorkflowData; +import com.amazon.alexa.auto.apis.auth.CodePair; + +import org.greenrobot.eventbus.EventBus; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.security.GeneralSecurityException; +import java.util.Optional; + +public class CBLAuthReceiver extends BroadcastReceiver { + private static final String TAG = CBLAuthReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + if (intent == null || intent.getAction() == null) { + return; + } + + //if intent is aacs state and not embedded intent handle it here + if (AACSConstants.ACTION_STATE_CHANGE.equals(intent.getAction())) { + //check if it is engine initialized and send start auth data if refresh token is present + String newState=""; + + if (intent.hasExtra("state")) { + newState = intent.getStringExtra("state"); + + if(newState.equals(AACSConstants.State.ENGINE_INITIALIZED.name())){ + EventBus.getDefault().post(new AuthWorkflowData(AuthState.Alexa_Client_Auth_Unintialized, null, null)); + } + } + + }else { + + AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { + + try{ + JSONObject obj = new JSONObject(message.payload); + String service = obj.getString(LWAAuthConstants.AUTH_SERVICE); + + if(service.equals(LWAAuthConstants.AUTH_CBL_SERVICE_NAME)) { + switch (message.action) { + case Action.Authorization.EVENT_RECEIVED: + handleAuthorizationEvent(context, obj); + break; + case Action.Authorization.AUTHORIZATION_STATE_CHANGED: + handleAuthorizationStateChanged(obj); + break; + case Action.Authorization.AUTHORIZATION_ERROR: + handleAuthorizationError(obj); + break; + case Action.Authorization.SET_AUTHORIZATION_DATA: + handleSetAuthorizationData(context, obj); + break; + case Action.Authorization.GET_AUTHORIZATION_DATA: + handleGetAuthorizationData(context, message); + break; + } + } + } + catch (JSONException e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + }); + } + } + + private void handleAuthorizationEvent(Context context, JSONObject obj) { + try { + String event = obj.getString("event"); + + JSONObject eventObj = new JSONObject(event); + String typeValue = eventObj.getString("type"); + + if (!typeValue.isEmpty() ) { + JSONObject payloadObj = new JSONObject(eventObj.getString("payload")); + + if(typeValue.equals("cbl-code")){ + String url =payloadObj.getString("url"); + String code = payloadObj.getString("code"); + + if (code.isEmpty() || url.isEmpty()) { + Log.w(TAG, "CBL code or URL empty."); + } + EventBus.getDefault().post( new AuthWorkflowData(AuthState.CBL_Auth_CodePair_Received, new CodePair(url, code), null)); + }else if( typeValue.equals("user-profile")){ + + String email = payloadObj.getString("email"); + String name = payloadObj.getString("name"); + + if (email.isEmpty() || name.isEmpty()) { + Log.w(TAG, "email or name empty."); + }else { + UserIdentityStore.saveUserIdentity(context, name); + //Need to check if we need to store email as well + EventBus.getDefault().post( + new AuthWorkflowData(AuthState.CBL_Auth_User_Identity_Saved, null, null)); + } + } + } + } catch (Exception e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + } + + private void handleAuthorizationStateChanged(JSONObject obj) { + try{ + String authState = obj.getString("state"); + + switch (authState) { + case "AUTHORIZING": + EventBus.getDefault().post(new AuthWorkflowData(AuthState.CBL_Auth_Started, null, null)); + break; + } + } catch (Exception e) { + Log.e(TAG, "handleAuthorizationStateChanged JSONException."); + } + } + + private void handleAuthorizationError(JSONObject obj) { + + try{ + String error = obj.getString("error"); + + switch (error) { + case "AUTH_FAILURE": + Log.w(TAG, "Auth token failure."); + break; + case "UNKNOWN_ERROR": + Log.e(TAG, "Unknown error AuthError message"); + break; + case "START_AUTHORIZATION_FAILED": + Log.e(TAG, "Start Authorization Failed"); + break; + case "LOGOUT_FAILED": + Log.e(TAG, "Logout Failed message"); + break; + } + } catch (Exception e) { + Log.e(TAG, "Authorization event JSON cannot be parsed."); + } + } + + private void handleSetAuthorizationData(Context context, JSONObject obj) { + + String refreshToken = ""; + try { + + String data = obj.getString("data"); + if(data.isEmpty()) { + Log.d(TAG, "handle clear authorization data"); + TokenStore.resetRefreshToken(context); + } else { + JSONObject dataObj = new JSONObject(data); + refreshToken = dataObj.getString("refreshToken"); + + if (refreshToken.isEmpty()) { + Log.w(TAG, "refreshToken is empty."); + } + + TokenStore.saveRefreshToken(context, refreshToken); + EventBus.getDefault().post(new AuthWorkflowData(AuthState.CBL_Auth_Token_Saved, null, null)); + } + } catch(Exception e) { + Log.e(TAG, "Failed to handle SetAuthorizationData. Exception: "); + return; + } + } + + private void handleGetAuthorizationData(Context context, AACSMessage message ) { + try { + + Optional refreshToken = TokenStore.getRefreshToken(context); + JSONObject payloadJson; + + payloadJson = new JSONObject(); + payloadJson.put("refreshToken", refreshToken.orElse("")); + + String payload = new JSONStringer() + .object() + .key("data") + .value(payloadJson.toString()) + .endObject() + .toString(); + new AACSMessageSender(new WeakReference<>(context), new AACSSender()) + .sendReplyMessage(message.messageId, Topic.AUTHORIZATION, Action.Authorization.GET_AUTHORIZATION_DATA, payload); + + } catch(Exception e) { + Log.e(TAG, "Failed to handle GetAuthorizationData. Exception: " + e.getMessage()); + return; + } + } +} + diff --git a/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthConstants.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthConstants.java new file mode 100644 index 000000000..4b35382d8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthConstants.java @@ -0,0 +1,26 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.alexa.auto.lwa; + +public class LWAAuthConstants { + + public static final String AUTH_PROVIDER_SERVICE_NAME = "alexa:auth-provider"; + public static final String AUTH_CBL_SERVICE_NAME = "alexa:cbl"; + public static final String AUTH_SERVICE = "service"; + public static final String AUTH_DATA = "data"; + +} + diff --git a/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthController.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthController.java new file mode 100644 index 000000000..4a35d37ae --- /dev/null +++ b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/LWAAuthController.java @@ -0,0 +1,496 @@ +package com.amazon.alexa.auto.lwa; + +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.util.Log; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.annotation.NonNull; + +import com.amazon.aacsconstants.AACSConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.aacsipc.IPCConstants; +import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.apis.auth.AuthController; +import com.amazon.alexa.auto.apis.auth.AuthMode; +import com.amazon.alexa.auto.apis.auth.AuthState; +import com.amazon.alexa.auto.apis.auth.AuthStatus; +import com.amazon.alexa.auto.apis.auth.AuthWorkflowData; +import com.amazon.alexa.auto.apis.auth.AuthorizationHandlerInterface; +import com.amazon.alexa.auto.apis.auth.UserIdentity; +import com.amazon.alexa.auto.apps.common.util.FileUtil; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONStringer; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.ObservableEmitter; +import io.reactivex.rxjava3.core.Single; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * Auth controller for Alexa authorization. + */ +public class LWAAuthController implements AuthController { + private static final String TAG = LWAAuthController.class.getSimpleName(); + + private WeakReference context; + private BehaviorSubject authStatusColdStream; + private AACSMessageSender messageSender; + private AuthMode mAuthMode; + private ExecutorService mExecutorService; + private Handler mMainThreadHandler; + private AlexaClientEventReceiver mAlexaClientEventReceiver; + private boolean mIsAlexaConnected; + private boolean mEnableUserProfile; + private BroadcastReceiver mCBLAuthReceiver; + /** + * Constructs the LWAAuthController. + */ + public LWAAuthController(WeakReference context) { + this.context = context; + authStatusColdStream = BehaviorSubject.create(); + messageSender = new AACSMessageSender(context, new AACSSender()); + + authStatusColdStream.onNext(new AuthStatus(isAuthenticated(), getUserIdentity())); + mAuthMode = AuthMode.CBL_AUTHORIZATION; + mIsAlexaConnected = false; + + mExecutorService = Executors.newSingleThreadExecutor(); + mMainThreadHandler = new Handler(Looper.getMainLooper()); + + getExtraAuthorizationHandlerFactoryAsync() + .filter(Optional::isPresent) + .map(Optional::get) + .subscribe((authHandlerFactory) -> { + for (AuthorizationHandlerInterface authorizationHandlerInterface : authHandlerFactory) { + authorizationHandlerInterface.initialize(this.context.get()); + } + }); + + subscribeAlexaClientConnectionStatus(); + + mCBLAuthReceiver = new CBLAuthReceiver(); + + IntentFilter filter = new IntentFilter(); + filter.addAction(AACSConstants.ACTION_STATE_CHANGE); + + (context.get()).registerReceiver(mCBLAuthReceiver, filter); + + FileUtil.readAACSConfigurationAsync(context.get()).subscribe(this::isCBLUserProfileEnabled); + } + + @Override + public void setAuthMode(AuthMode authMode) { + mAuthMode = authMode; + } + + @Override + public AuthMode getAuthMode() { + return mAuthMode; + } + + @Override + public boolean isAuthenticated() { + Context contextStrong = context.get(); + if (contextStrong == null) { + throw new RuntimeException("Context not valid any more."); + } + + try { + return TokenStore.getRefreshToken(contextStrong).isPresent(); + } catch (GeneralSecurityException | IOException e) { + Log.e(TAG, "Failed to get refresh token."); + return false; + } + } + + @Override + public void setAuthState(AuthStatus authStatus) { + authStatusColdStream.onNext(authStatus); + } + + @Override + public Observable newAuthenticationWorkflow() { + return Observable.create(emitter -> { + class AuthEventReceiver { + @Subscribe + public void OnReceive(AuthWorkflowData data) { + emitter.onNext(data); + switch (data.getAuthState()) { + case Auth_Provider_Auth_Started: + mAuthMode = AuthMode.AUTH_PROVIDER_AUTHORIZATION; + if (!startLoginWorkflow()) { + emitter.onError(new Exception("Failed to start Login workflow")); + } + break; + case Alexa_Client_Connected: + // When Alexa is connected, and the auth token has also been saved, we will send the auth + // finished/authorized event to subscribers. + if (isAuthenticated()) { + publishAuthFinishedStatus(emitter); + } + break; + case CBL_Auth_User_Identity_Saved: + case Auth_Provider_Token_Saved: + // When CBL user identity or other authorization provider's auth token is saved, we want to + // make sure Alexa connection is also established with the user identity or token, then we + // send the auth finished/authorized event to subscribers. + if (mIsAlexaConnected) { + publishAuthFinishedStatus(emitter); + } + break; + case CBL_Auth_Token_Saved: + if (mEnableUserProfile) { + // If user profile is enabled, we need to make sure we have also saved user identity on + // the device, so that we can get the user name and display it on the screen when + // needed. + Log.d(TAG, + "User profile is enabled, waiting for user identity to be saved successfully."); + } else { + if (mIsAlexaConnected) { + // If user profile is disabled, we can send the CBL_Auth_Finished event now. + emitter.onNext(new AuthWorkflowData(AuthState.CBL_Auth_Finished, null, null)); + authStatusColdStream.onNext(new AuthStatus(isAuthenticated(), getUserIdentity())); + } + } + break; + } + } + } + + AuthEventReceiver eventReceiver = new AuthEventReceiver(); + EventBus.getDefault().register(eventReceiver); + + if (mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + emitter.onNext(new AuthWorkflowData(AuthState.CBL_Auth_Not_Started, null, null)); + } + if (!startLoginWorkflow()) { + emitter.onError(new Exception("Failed to start Login workflow")); + } + + emitter.setCancellable(() -> { + EventBus.getDefault().unregister(eventReceiver); + + // When subscriber has cancelled the workflow. + if (!isAuthenticated()) { + cancelLoginWorkflow(); + } + }); + }); + } + + @Override + public Observable observeAuthChangeOrLogOut() { + return authStatusColdStream; + } + + @Override + public void logOut() { + Context strongContext = context.get(); + String service = ""; + + if (strongContext == null) { + Log.w(TAG, "Cannot cancel login workflow. Context is invalid"); + return; + } + + Log.d(TAG, "Resetting the login state"); + + if (mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_CBL_SERVICE_NAME; + } else if (mAuthMode.equals(AuthMode.AUTH_PROVIDER_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_PROVIDER_SERVICE_NAME; + } + try { + String payload = new JSONStringer() + .object() + .key(LWAAuthConstants.AUTH_SERVICE) + .value(service) + .endObject() + .toString(); + messageSender.sendMessage(Topic.AUTHORIZATION, Action.Authorization.LOGOUT, payload); + } catch (JSONException e) { + Log.e(TAG, "Fail to generate authorization logout message."); + } + + + try { + TokenStore.resetRefreshToken(strongContext); + } catch (GeneralSecurityException | IOException e) { + Log.e(TAG, "Failed to reset refresh token."); + } + + try { + UserIdentityStore.resetUserIdentity(strongContext); + } catch (GeneralSecurityException | IOException e) { + Log.e(TAG, "Failed to reset user identity."); + } + + + authStatusColdStream.onNext(new AuthStatus(false, null)); + } + + @Override + public void cancelLogin(AuthMode mode) { + Context strongContext = context.get(); + String service = ""; + + if (strongContext == null) { + Log.w(TAG, "Cannot cancel login workflow. Context is invalid"); + return; + } + + Log.d(TAG, "Cancelling the login state"); + + if (mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_CBL_SERVICE_NAME; + } else if (mAuthMode.equals(AuthMode.AUTH_PROVIDER_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_PROVIDER_SERVICE_NAME; + } + + try { + String payload = new JSONStringer() + .object() + .key(LWAAuthConstants.AUTH_SERVICE) + .value(service) + .endObject() + .toString(); + messageSender.sendMessage(Topic.AUTHORIZATION, Action.Authorization.LOGOUT, payload); + } catch (JSONException e) { + Log.e(TAG, "Fail to generate authorization logout message."); + } + } + + @Override + public UserIdentity getUserIdentity() { + if (mAuthMode != null) { + if (isAuthenticated() && mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + try { + String userName = UserIdentityStore.getUserIdentity(context.get()); + + if (userName != null) { + return new UserIdentity(userName); + } + return null; + } catch (GeneralSecurityException | IOException e) { + Log.e(TAG, "Fail to get user identity data."); + return null; + } + } else { + Log.w(TAG, "Device is not authenticated or it is not for CBL login, we cannot get user identity data."); + return null; + } + } + return null; + } + + private boolean startLoginWorkflow() { + Context strongContext = context.get(); + String service = ""; + + if (strongContext == null) { + Log.w(TAG, "Cannot start login workflow. Context is invalid"); + return false; + } + + // Then send a Start request. + Log.i(TAG, "Starting new Login workflow"); + + if (mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_CBL_SERVICE_NAME; + } else if (mAuthMode.equals(AuthMode.AUTH_PROVIDER_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_PROVIDER_SERVICE_NAME; + } + + try { + String payload = new JSONStringer() + .object() + .key(LWAAuthConstants.AUTH_SERVICE) + .value(service) + .key(LWAAuthConstants.AUTH_DATA) + .value("") + .endObject() + .toString(); + messageSender.sendMessage(Topic.AUTHORIZATION, Action.Authorization.START_AUTHORIZATION, payload); + } catch (JSONException e) { + Log.e(TAG, "Fail to generate start authorization message."); + } + return true; + } + + private void cancelLoginWorkflow() { + Context strongContext = context.get(); + String service = ""; + + if (strongContext == null) { + Log.w(TAG, "Cannot start login workflow. Context is invalid"); + return; + } + + Log.i(TAG, "Cancelling the login workflow (if prior login workflow exists)."); + + if (mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_CBL_SERVICE_NAME; + } else if (mAuthMode.equals(AuthMode.AUTH_PROVIDER_AUTHORIZATION)) { + service = LWAAuthConstants.AUTH_PROVIDER_SERVICE_NAME; + } + + try { + String payload = new JSONStringer() + .object() + .key(LWAAuthConstants.AUTH_SERVICE) + .value(service) + .endObject() + .toString(); + messageSender.sendMessage(Topic.AUTHORIZATION, Action.Authorization.CANCEL_AUTHORIZATION, payload); + } catch (JSONException e) { + Log.e(TAG, "Fail to generate cancel authorization message."); + } + } + + private Single>> getExtraAuthorizationHandlerFactoryAsync() { + return Single.create(emitter -> { + mExecutorService.submit(() -> { + Optional> handlerFactoryOptional = + getExtraAuthorizationHandlerFactorySync(context.get()); + mMainThreadHandler.post(() -> emitter.onSuccess(handlerFactoryOptional)); + }); + }); + } + + private Optional> getExtraAuthorizationHandlerFactorySync(Context context) { + List extraAuthorizationHandlerFactories = new ArrayList<>(); + try { + String folderName = "auth-handler"; + String factoryKey = "authorizationHandlerFactory"; + String category = "name"; + String[] fileList = context.getAssets().list(folderName); + for (String f : fileList) { + InputStream is = context.getAssets().open(folderName + "/" + f); + byte[] buffer = new byte[is.available()]; + is.read(buffer); + String json = new String(buffer, "UTF-8"); + JSONObject obj = new JSONObject(json); + if (obj != null) { + JSONObject factoryKeyObj = obj.optJSONObject(factoryKey); + if (factoryKeyObj == null) { + continue; + } + String factoryName = factoryKeyObj.getString(category); + AuthorizationHandlerInterface instance = + (AuthorizationHandlerInterface) Class.forName(factoryName).newInstance(); + extraAuthorizationHandlerFactories.add(instance); + Log.i(TAG, "getExtraAuthorizationHandlerFactory: load extra module:" + factoryName); + } + is.close(); + } + } catch (Exception e) { + Log.e(TAG, "getExtraAuthorizationHandlerFactory: " + e.getMessage()); + return Optional.empty(); + } + return Optional.of(extraAuthorizationHandlerFactories); + } + + private void isCBLUserProfileEnabled(@NonNull String configs) { + try { + JSONObject config = new JSONObject(configs); + String mUserProfileConfig = config.getJSONObject("aacs.cbl").getString("enableUserProfile"); + mEnableUserProfile = mUserProfileConfig.equals("true"); + } catch (JSONException e) { + Log.w(TAG, "Failed to parse enableUserProfile config" + e); + } + } + + private void publishAuthFinishedStatus(ObservableEmitter emitter) { + + if (mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + emitter.onNext(new AuthWorkflowData(AuthState.CBL_Auth_Finished, null, null)); + } else { + emitter.onNext( + new AuthWorkflowData(AuthState.Auth_Provider_Authorized, null, null)); + } + authStatusColdStream.onNext(new AuthStatus(isAuthenticated(), getUserIdentity())); + } + + /** + * Subscribe Alexa client connection event during the app life cycle, user can choose to finish CBL login + * with phone and skip the CBL login steps from the head unit app. When user finishes CBL login with phone, + * and Alexa client connection state changes to CONNECTED, the Alexa client connected event will be sent and + * captured by AlexaClientEventReceiver, and the remaining setup steps will be triggered from the app. + */ + public void subscribeAlexaClientConnectionStatus() { + if (mAlexaClientEventReceiver == null) { + mAlexaClientEventReceiver = new AlexaClientEventReceiver(); + EventBus.getDefault().register(mAlexaClientEventReceiver); + } + } + + class AlexaClientEventReceiver { + @Subscribe + public void OnReceive(AuthWorkflowData data) { + if (data.getAuthState().equals(AuthState.Alexa_Client_Connected)) { + setAuthState(new AuthStatus(isAuthenticated(), getUserIdentity())); + mIsAlexaConnected = true; + } else if (data.getAuthState().equals(AuthState.Alexa_Client_Disconnected)) { + mIsAlexaConnected = false; + } else if(data.getAuthState().equals(AuthState.Alexa_Client_Auth_Unintialized)){ + + if(mAuthMode.equals(AuthMode.CBL_AUTHORIZATION)) { + Log.w(TAG, "AuthState.Alexa_Client_Auth_Unintialized authmode = " + mAuthMode ); + //check if we have a valid refresh token then send start authorization + try { + Context contextStrong = context.get(); + if (contextStrong == null) { + throw new RuntimeException("Context not valid any more."); + } + + Optional refreshToken = TokenStore.getRefreshToken(contextStrong); + + if(refreshToken.isPresent()){ + Log.w(TAG, "refreshToken.isPresent() "); + try { + JSONObject payloadJson; + payloadJson = new JSONObject(); + payloadJson.put("refreshToken", refreshToken.orElse("")); + Log.w(TAG, "refreshToken.isPresent() refreshToken="+ refreshToken); + String payload = new JSONStringer() + .object() + .key(LWAAuthConstants.AUTH_SERVICE) + .value(LWAAuthConstants.AUTH_CBL_SERVICE_NAME) + .key(LWAAuthConstants.AUTH_DATA) + .value(payloadJson.toString()) + .endObject() + .toString(); + messageSender.sendMessage(Topic.AUTHORIZATION, Action.Authorization.START_AUTHORIZATION, payload); + } catch (JSONException e) { + Log.e(TAG, "Fail to generate start authorization message."); + } + } + } catch (GeneralSecurityException | IOException e) { + Log.e(TAG, "Failed to get refresh token."); + } + } + } + } + } +} diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/TokenStore.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/TokenStore.java similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/TokenStore.java rename to aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/TokenStore.java diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/UserIdentityStore.java b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/UserIdentityStore.java similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/UserIdentityStore.java rename to aacs/android/app-components/alexa-auto-lwa-auth/src/main/java/com/amazon/alexa/auto/lwa/UserIdentityStore.java diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-lwa-auth/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-lwa-auth/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/.gitignore b/aacs/android/app-components/alexa-auto-media-player/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/.gitignore rename to aacs/android/app-components/alexa-auto-media-player/.gitignore diff --git a/aacs/android/app-components/alexa-auto-media-player/README.md b/aacs/android/app-components/alexa-auto-media-player/README.md new file mode 100644 index 000000000..920218ad8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/README.md @@ -0,0 +1,74 @@ +# Alexa Auto Media Player + +## Table of Contents +- [Alexa Auto Media Player](#alexa-auto-media-player) +- [Include Alexa Auto Media Player in the Application](#include-alexa-auto-media-player-in-the-application) +- [Enable Media Ducking](#enable-media-ducking) +- [Media Resume Alexa Music After Reboot](#media-resume-alexa-music-after-reboot) +- [Login from Android Automotive Media UI](#login-from-android-automotive-media-ui) +- [Alexa Music Certification](#alexa-music-certification) + +## Alexa Auto Media Player +The following list describes the purposes of this package: +* It provides the audio player capability for Alexa Auto Client Service (AACS) by receiving all audio player intents and notifying AACS about the progress of media playback. +* It manages the underlying media player, which is ExoPlayer. +* It handles audio focus. +* It implements a media session on top of the media player so that media can be controlled with standard Android Media Session APIs. This capability allows Alexa Media to integrate with the Android Automotive Media UI. + +## Include Alexa Auto Media Player in the Application +The Alexa Auto Media Player is by default enabled in the AACS Sample App. See the [AACS Sample App README](../../sample-app/README.md#building-and-signing-the-aacs-sample-app-apk) for build instructions. + +If you want to use Alexa Auto Media Player in your application, build the following app components and include all the generated AARs in your application: +* alexa-auto-apis +* alexa-auto-apps-common-ui +* alexa-auto-apps-common-util +* alexa-auto-media-player + +## Enable Media Ducking +You can enable audio ducking for the Alexa media using this configuration. By default, Alexa pauses `MUSIC` channel whenever Alexa `TTS` or `ALARM` channels are in the focus. Enabling ducking allows `MUSIC` channel to remain in the playing state when high priority channels like `TTS` and `ALARM` are active. For enabling ducking, please provide the following configuration: + +```JSON +{ + "aacs.alexa" : { + "audioOutputType.music": { + "ducking": { + "enabled" : true + } + } + } +} +``` + +## Media Resume Alexa Music After Reboot +Please refer to [Media Resume Last Playing Media After Platform Reboot](../../sample-app/README.md#media-resume-last-playing-media-after-platform-reboot) for the details about media resume feature. This feature works out of the box on Automotive Android OS with this component. Following configuration is required to enable and use this feature: + +```JSON +"aacs.alexa": { + "requestMediaPlayback": { + "mediaResumeThreshold": 50000 + } +} +``` + +## Login from Android Automotive Media UI +This library provides an optional feature that enables the Android Automotive Media UI to display the "not authenticated" message if the app is not authenticated. It then offers the option for the user to invoke the login UI workflow. + +To enable this feature in the app with this library, implement `AlexaApp`, a registry interface defined in the Alexa Auto APIs package, and resolve dependencies by using the following interfaces: + * `AuthController`: This interface provides business logic to monitor the current authentication state (the value of `loggedIn`). The interface is made available from `AlexaAppRootComponent`. + * `AlexaSetupController`: This interface enables the media UI to launch the login UI activity if the authentication state indicates that the user is not logged in. + +>**Note:** See the [alexa-auto-apis README](../alexa-auto-apis/README.md) for more information about consuming and publishing implementations. + +## Alexa Music Certification +This version of the Alexa Auto Media Player doesn’t meet all the Alexa Music Certification requirements on Android Automotive OS. It passes API validation for Amazon Music, Audible, Kindle, TuneIn Radio Live, TuneIn Radio Custom, Music Skills (Deezer & SiriusXM), iHeart Radio Live, and iHeart Radio Custom. Pandora doesn’t have an API validation requirement. + +The Media Player doesn’t pass Music Service Provider (MSP) logo attribution GUI validation for Amazon Music, TuneIn Radio Live, TuneIn Radio Custom, Music Skills (Deezer & SiriusXM), iHeart Radio Live, iHeart Radio Custom, and Pandora. Audible and Kindle don't have a GUI validation requirement. The Android Automotive OS doesn't have placeholder for showing MSP logo which is required for passing GUI validation. The Media Player provides text based MSP attribution. + +The Android Automotive OS displays album art as the background image in media player screen, which doesn't pass GUI validation of not altering album art in any way. + +Due to the missing media controls in TemplateRuntime RenderPlayerInfo payload, the Media Player fails to display all the required media controls, which doesn't pass media controls GUI validation. + +The standard certification process is required and simplified by the Alexa Auto Media Player because the above mentioned API validation has been completed. Contact your Solutions Architect (SA) or Partner Manager for information about how to obtain certification. + +## Known Issues +* On low resolution screens, Music Service Provider (MSP) name may cut-off when artist string is long. \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-media-player/build.gradle b/aacs/android/app-components/alexa-auto-media-player/build.gradle new file mode 100644 index 000000000..3261c8bbf --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/build.gradle @@ -0,0 +1,89 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 30 + defaultConfig { + minSdkVersion 26 + targetSdkVersion 30 + versionCode 1 + versionName "4.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-media-player" + def separator = "_" + def buildType = variant.buildType.name + def aarName = project + separator + buildType + ".aar" + outputFileName = new File(aarName) + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + repositories { + flatDir { + dirs 'libs' + } + } +} + +dependencies { + // AACS Client Libraries + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':aacscommonutils') + + implementation project(":alexa-auto-apis") + implementation project(':alexa-auto-apps-common-ui') + implementation project(':alexa-auto-apps-common-util') + + implementation deps.androidx_core + implementation deps.androidx_media + + // Kotlin + implementation deps.kotlin_stdlib + implementation deps.androidx_core_ktx + + // Dagger + implementation deps.dagger + kapt deps.dagger_compiler + + // Exo Player + implementation deps.exoplayer_core + implementation deps.exoplayer_dash + implementation deps.exoplayer_smooth + implementation deps.exoplayer_hls + + // RX + implementation deps.rxjava3 + + // Glide (loading images) + implementation deps.glide + + //Test Dependencies + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.mockito_nhaarman + testImplementation deps.androidx_test_core + testImplementation deps.roboelectric +} diff --git a/platforms/android/app-components/alexa-auto-comms-ui/proguard-rules.pro b/aacs/android/app-components/alexa-auto-media-player/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-comms-ui/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-media-player/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a86dd1570 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/AndroidManifest.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/Constants.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/Constants.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/Constants.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/Constants.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/MusicStreamAttributeUpdater.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/MusicStreamAttributeUpdater.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/MusicStreamAttributeUpdater.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/MusicStreamAttributeUpdater.java diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/ShutdownActionReceiver.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/ShutdownActionReceiver.java new file mode 100644 index 000000000..f36f0d2e9 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/ShutdownActionReceiver.java @@ -0,0 +1,61 @@ +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.alexa.auto.media; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.util.Log; + +import com.amazon.alexa.auto.media.session.MediaSessionManager; + +import java.lang.ref.WeakReference; + +public class ShutdownActionReceiver extends BroadcastReceiver { + private static final String TAG = "ShutdownActionReceiver"; + private MediaSessionManager mMediaSessionManager; + + private WeakReference mContext; + + private IntentFilter mIntentFilter; + + public ShutdownActionReceiver(WeakReference context) { + mContext = context; + mIntentFilter = new IntentFilter(); + mIntentFilter.addAction(Intent.ACTION_SHUTDOWN); + } + + @Override + public void onReceive(Context context, Intent intent) { + if (intent != null && intent.getAction().equalsIgnoreCase(Intent.ACTION_SHUTDOWN)) { + if (mMediaSessionManager != null) { + mMediaSessionManager.shutdown(); + } else { + Log.e(TAG, "MediaSessionManager is null"); + } + } + } + + public void onCreate(MediaSessionManager manager) { + mMediaSessionManager = manager; + mContext.get().registerReceiver(this, mIntentFilter); + } + + public void onDestroy() { + mContext.get().unregisterReceiver(this); + } +} diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/AudioPlayerHandler.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/AudioPlayerHandler.java new file mode 100644 index 000000000..6acfaf1be --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/AudioPlayerHandler.java @@ -0,0 +1,354 @@ +package com.amazon.alexa.auto.media.aacs.handlers; + +import android.net.Uri; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.amazon.aacsconstants.AASBConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.MediaConstants; +import com.amazon.aacsconstants.PlaybackConstants; +import com.amazon.aacsconstants.Topic; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.aacs.common.PlaybackControlMessages; +import com.amazon.alexa.auto.apps.common.util.Preconditions; +import com.amazon.alexa.auto.media.MusicStreamAttributeUpdater; +import com.amazon.alexa.auto.media.player.MediaPlayerAudioFocusController; +import com.amazon.alexa.auto.media.player.MediaPlayerExo; + +import org.json.JSONObject; +import org.json.JSONStringer; + +/** + * Handler for AudioPlayer commands coming from AACS. + */ +public class AudioPlayerHandler implements AutoCloseable, IMediaDuckingObserver { + private final static String TAG = AudioPlayerHandler.class.getSimpleName(); + private final static String AUDIO_PLAYER_CHANNEL = "AudioPlayer"; + + // Dependencies. + @NonNull + private final AACSMessageSender mAACSSender; + @NonNull + private final MediaPlayerExo mTargetMediaPlayer; + @NonNull + private final MediaPlayerAudioFocusController mAudioFocusController; + @NonNull + private final PlaybackControlMessages mPlaybackControlMessages; + @NonNull + private final MusicStreamAttributeUpdater mMusicStreamAttributeUpdater; + + // Internal Dependencies. + @NonNull + private final AudioFocusPlaybackController mAudioFocusPlaybackController; + + // State. + private String currentSourceToken; + + /** + * Constructs the AACS AudioPlayer commands handler. + * + * @param sender To send messages back to AACS. + * @param targetMediaPlayer Target media player. + * @param audioFocusController Manages audio focus for playback. + * @param playbackControlMessages For sending playback control messages to AACS. + * @param musicStreamAttributeUpdater Helper to change volume for music stream. + */ + public AudioPlayerHandler(@NonNull AACSMessageSender sender, @NonNull MediaPlayerExo targetMediaPlayer, + @NonNull MediaPlayerAudioFocusController audioFocusController, + @NonNull PlaybackControlMessages playbackControlMessages, + @NonNull MusicStreamAttributeUpdater musicStreamAttributeUpdater) { + mAACSSender = sender; + mTargetMediaPlayer = targetMediaPlayer; + mAudioFocusController = audioFocusController; + mPlaybackControlMessages = playbackControlMessages; + mMusicStreamAttributeUpdater = musicStreamAttributeUpdater; + + mAudioFocusPlaybackController = new AudioFocusPlaybackController(); + mAudioFocusController.setPlaybackController(mAudioFocusPlaybackController); + } + + @Override + public void close() throws Exception { + mAudioFocusController.close(); + } + + /** + * Handle commands coming from AACS. + * + * @param message AACS Message. + */ + public void handleAACSCommand(@NonNull AACSMessage message) { + switch (message.action) { + case Action.AudioOutput.PREPARE: + handlePrepare(message.messageId, message.payload); + break; + case Action.AudioOutput.MAY_DUCK: + handleMayDuck(); + break; + case Action.AudioOutput.PAUSE: + pauseAndDisableAutoPlay(); + break; + case Action.AudioOutput.STOP: + handleStop(); + break; + case Action.AudioOutput.PLAY: + mAudioFocusController.resetAudioFocusRequest(); + case Action.AudioOutput.RESUME: + mAudioFocusController.startPlaybackAfterAcquiringFocus(); + break; + case Action.AudioOutput.START_DUCKING: + mAudioFocusController.startDucking(); + break; + case Action.AudioOutput.STOP_DUCKING: + mAudioFocusController.stopDucking(); + break; + case Action.AudioOutput.GET_POSITION: + handleGetPosition(message.messageId, message.payload); + break; + case Action.AudioOutput.GET_DURATION: + handleGetDuration(message.messageId, message.payload); + break; + case Action.AudioOutput.SET_POSITION: + handleSetPosition(message.messageId, message.payload); + break; + case Action.AudioOutput.VOLUME_CHANGED: + handleChangeVolume(message.messageId, message.payload); + break; + case Action.AudioOutput.MUTED_STATE_CHANGED: + handleSetMuteState(message.messageId, message.payload); + break; + default: + throw new RuntimeException(String.format("Unrecognized audio manager command %s", message.action)); + } + } + + /** + * Process media state change and also publish the new media state to AACS. + * + * @param state New state to publish. + */ + public void processMediaStateChange(String state) { + try { + if (MediaConstants.MediaState.STOPPED.equals(state)) { + Log.d(TAG, "Media state is stopped. Disabling auto playback"); + pauseAndDisableAutoPlay(); + } + + String payload = new JSONStringer() + .object() + .key(MediaConstants.CHANNEL) + .value(AUDIO_PLAYER_CHANNEL) + .key(MediaConstants.TOKEN) + .value(this.currentSourceToken) + .key(MediaConstants.STATE) + .value(state) + .endObject() + .toString(); + + Log.d(TAG, "publishing media state to AACS. state:" + state); + mAACSSender.sendMessage(Topic.AUDIO_OUTPUT, Action.AudioOutput.MEDIA_STATE_CHANGED, payload); + } catch (Exception e) { + Log.e(TAG, "failed to create mediaStateChanged JSON payload."); + } + } + + @Override + public void reportClientDuckingState(boolean isDucked) { + try { + String payload = new JSONStringer() + .object() + .key(MediaConstants.CHANNEL) + .value(AUDIO_PLAYER_CHANNEL) + .key(MediaConstants.TOKEN) + .value(this.currentSourceToken) + .key(MediaConstants.FOCUS_ACTION) + .value(isDucked ? MediaConstants.AudioFocusEvent.REPORT_DUCKING_STARTED + : MediaConstants.AudioFocusEvent.REPORT_DUCKING_STOPPED) + .endObject() + .toString(); + + Log.d(TAG, "publishing ducking state to AACS. state:" + (isDucked ? "Ducked" : "Unducked")); + mAACSSender.sendMessage(Topic.AUDIO_OUTPUT, Action.AudioOutput.AUDIO_FOCUS_EVENT, payload); + } catch (Exception e) { + Log.e(TAG, "failed to create AudioFocusEvent JSON payload."); + } + } + /** + * Process the media error and publish it to AACS. + * + * @param error Error to process. + */ + public void processMediaError(String error) { + try { + Log.d(TAG, "Media errored. Disabling auto playback. Error: " + error); + pauseAndDisableAutoPlay(); + + String payload = new JSONStringer() + .object() + .key(MediaConstants.CHANNEL) + .value(AUDIO_PLAYER_CHANNEL) + .key(MediaConstants.TOKEN) + .value(this.currentSourceToken) + .key(MediaConstants.MEDIA_ERROR) + .value(MediaConstants.MediaError.MEDIA_ERROR_UNKNOWN) + .key(MediaConstants.ERROR_DESCRIPTION) + .value(error) + .endObject() + .toString(); + + Log.d(TAG, "publishing media error to AACS. error:" + error); + mAACSSender.sendMessage(Topic.AUDIO_OUTPUT, Action.AudioOutput.MEDIA_ERROR, payload); + } catch (Exception e) { + Log.e(TAG, "failed to create mediaError JSON payload."); + } + } + + private void handlePrepare(@NonNull String messageId, @Nullable String payload) { + try { + Preconditions.checkNotNull(payload); + mAudioFocusController.setMixability(false, this); + JSONObject payloadJson = new JSONObject(payload); + boolean repeating = payloadJson.getBoolean(AASBConstants.AudioOutput.REPEATING); + String token = payloadJson.getString(AASBConstants.AudioOutput.TOKEN); + if (payloadJson.has(AASBConstants.AudioOutput.URL)) { + String url = payloadJson.getString(AASBConstants.AudioOutput.URL); + Log.d(TAG, String.format("Preparing media player with %s", url)); + mTargetMediaPlayer.prepare(Uri.parse(url)); + this.currentSourceToken = token; + } else { + Log.e(TAG, "Prepare json didn't have url:" + payload); + } + } catch (Exception e) { + Log.e(TAG, "failed to prepare, " + e.toString()); + } + } + + private void handleMayDuck() { + mAudioFocusController.setMixability(true, this); + } + + /** + * Disable auto playback such that next prepare request doesn't auto start + * the playback until distinct play signal is received from AACS. + */ + private void pauseAndDisableAutoPlay() { + mTargetMediaPlayer.requestPause(); + mAudioFocusController.relinquishAudioFocusIfCurrentlyAcquired(); + } + + private void handleStop() { + MediaPlayerExo targetMediaPlayer = mTargetMediaPlayer; + if (targetMediaPlayer.isStopped()) { + processMediaStateChange(MediaConstants.MediaState.STOPPED); + } else { + targetMediaPlayer.requestStop(); + } + mAudioFocusController.relinquishAudioFocusIfCurrentlyAcquired(); + } + + private void handleGetDuration(@NonNull String messageId, @Nullable String payload) { + try { + long duration = mTargetMediaPlayer.getDuration(); + String replyPayload = + new JSONStringer().object().key(MediaConstants.DURATION).value(duration).endObject().toString(); + + mAACSSender.sendReplyMessage(messageId, Topic.AUDIO_OUTPUT, Action.AudioOutput.GET_DURATION, replyPayload); + } catch (Exception e) { + Log.e(TAG, "failed to create getDurationReply JSON payload. Error: " + e); + } + } + + private void handleGetPosition(@NonNull String messageId, @Nullable String payload) { + try { + long positionMs = mTargetMediaPlayer.getPosition(); + String replyPayload = + new JSONStringer().object().key(MediaConstants.POSITION).value(positionMs).endObject().toString(); + + Log.d(TAG, "Dispatching current media position to AACS. Position:" + positionMs); + mAACSSender.sendReplyMessage(messageId, Topic.AUDIO_OUTPUT, Action.AudioOutput.GET_POSITION, replyPayload); + } catch (Exception e) { + Log.e(TAG, "failed to create getPositionReply JSON payload. Error: " + e); + } + } + + private void handleSetPosition(@NonNull String messageId, @Nullable String payload) { + Preconditions.checkArgument(payload != null && !payload.isEmpty()); + + try { + JSONObject jsonPayload = new JSONObject(payload); + + long position = jsonPayload.getLong(AASBConstants.AudioOutput.POSITION); + Log.d(TAG, "Setting position:" + position); + if (position > 0) { + mTargetMediaPlayer.seekToPosition(position); + } + } catch (Exception e) { + Log.e(TAG, "failed to set position"); + } + } + + private void handleChangeVolume(@NonNull String messageId, @Nullable String payload) { + try { + Preconditions.checkArgument(payload != null && !payload.isEmpty()); + + JSONObject jsonObject = new JSONObject(payload); + double volume = jsonObject.getDouble(AASBConstants.AudioOutput.VOLUME); + mMusicStreamAttributeUpdater.changeVolumeForMusicStream(volume); + } catch (Exception exception) { + Log.w(TAG, String.format("Failed to change volume %s", exception.toString())); + } + } + + private void handleSetMuteState(@NonNull String messageId, @Nullable String payload) { + try { + Preconditions.checkArgument(payload != null && !payload.isEmpty()); + + JSONObject jsonObject = new JSONObject(payload); + String state = jsonObject.getString(AASBConstants.AudioOutput.STATE); + mMusicStreamAttributeUpdater.setMuteForMusicStream("MUTED".equals(state)); + } catch (Exception exception) { + Log.w(TAG, String.format("Failed to change volume %s", exception.toString())); + } + } + + /** + * Playback controller for Audio Focus. + */ + private class AudioFocusPlaybackController implements MediaPlayerAudioFocusController.PlaybackController { + @Override + public void startPlaybackNow() { + mTargetMediaPlayer.requestPlay(); + } + + @Override + public void requestResumingPlayback() { + mPlaybackControlMessages.sendButtonCommandToAACS(PlaybackConstants.PlaybackButton.PLAY); + } + + @Override + public void requestPausePlayback() { + mPlaybackControlMessages.sendButtonCommandToAACS(PlaybackConstants.PlaybackButton.PAUSE); + } + + @Override + public void requestStopPlayback() { + mPlaybackControlMessages.sendButtonCommandToAACS(PlaybackConstants.PlaybackButton.PAUSE); + } + + @Override + public void adjustPlaybackVolume(float multiplier) { + mTargetMediaPlayer.setVolume(multiplier); + } + + @Override + public void failedToAcquireFocus() { + String errorMsg = "Failed to acquire audio focus"; + Log.w(TAG, errorMsg); + processMediaError(errorMsg); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/IMediaDuckingObserver.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/IMediaDuckingObserver.java new file mode 100644 index 000000000..51ec7d5ca --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/IMediaDuckingObserver.java @@ -0,0 +1,3 @@ +package com.amazon.alexa.auto.media.aacs.handlers; + +public interface IMediaDuckingObserver { public void reportClientDuckingState(boolean isDucked); } diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/TemplateRuntimeHandler.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/TemplateRuntimeHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/TemplateRuntimeHandler.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/aacs/handlers/TemplateRuntimeHandler.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java similarity index 77% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java index a3ca0a238..e5c5bb9c2 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseService.java @@ -24,8 +24,10 @@ import com.amazon.alexa.auto.apis.app.AlexaApp; import com.amazon.alexa.auto.apis.auth.AuthController; import com.amazon.alexa.auto.apis.setup.AlexaSetupController; +import com.amazon.alexa.auto.apps.common.util.FileUtil; import com.amazon.alexa.auto.apps.common.util.Preconditions; import com.amazon.alexa.auto.media.R; +import com.amazon.alexa.auto.media.ShutdownActionReceiver; import com.amazon.alexa.auto.media.aacs.handlers.AudioPlayerHandler; import com.amazon.alexa.auto.media.aacs.handlers.TemplateRuntimeHandler; import com.amazon.alexa.auto.media.dependencies.AndroidModule; @@ -37,6 +39,9 @@ import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.Player; +import org.json.JSONException; +import org.json.JSONObject; + import java.util.ArrayList; import java.util.List; @@ -54,8 +59,12 @@ public class AlexaMediaBrowseService extends MediaBrowserServiceCompat { // Idle timeout until service can remain up while idle. If service doesn't get // busy during this time, then service is stopped. public static final long SERVICE_IDLE_TIMEOUT_MS = 1000 * 60 * 30; // 30 minutes. - public static final String MEDIA_ID = "media-id"; + private static final String MEDIA_ID = "media-id"; + // Configuration file keys + private static final String AACS_ALEXA = "aacs.alexa"; + private static final String REQUEST_MEDIA_PLAYBACK = "requestMediaPlayback"; + private static final String MEDIA_RESUME_THRESHOLD = "mediaResumeThreshold"; // External Dependencies. @Inject @@ -70,6 +79,8 @@ public class AlexaMediaBrowseService extends MediaBrowserServiceCompat { AudioPlayerHandler mAudioPlayerHandler; @Inject TemplateRuntimeHandler mTemplateruntimeHandler; + @Inject + ShutdownActionReceiver mShutdownActionReceiver; // Internal Dependencies. private MediaPlayerEventListener mMediaPlayerEventListener; @@ -82,6 +93,8 @@ public class AlexaMediaBrowseService extends MediaBrowserServiceCompat { private Disposable mAuthSubscription; @Nullable private Disposable mVASelectionSubscription; + @Nullable + private Disposable mAACSConfigDisposable; /** * Creates an instance of Service. @@ -105,18 +118,26 @@ MediaPlayerEventListener getEventListener() { public void onCreate() { super.onCreate(); Log.d(TAG, "onCreate"); - + mAACSConfigDisposable = + FileUtil.readAACSConfigurationAsync(getApplicationContext()).subscribe(this::checkMediaResume); DaggerMediaComponent.builder() .androidModule(new AndroidModule(getApplicationContext())) .build() .injectMediaBrowseService(this); - - mMediaSessionManager.activateMediaSession(); setSessionToken(mMediaSessionManager.getMediaSession().getSessionToken()); - - initializeMediaSessionWithErrorForGuidingUser(); + if (mMediaSessionManager.mayAutoResume()) { + mMediaSessionManager.setupMediaResume(); + mMediaSessionManager.setupMediaSessionCallbacks(); + mServiceLifecycle.startServiceWithIdleTimer(); + } else { + mMediaSessionManager.activateMediaSession(); + mMediaSessionManager.setupMediaSessionCallbacks(); + // If media session is enabled, do not set playback state error + initializeMediaSessionWithErrorForGuidingUser(); + } mMediaPlayer.getPlayer().addListener(mMediaPlayerEventListener); + mShutdownActionReceiver.onCreate(mMediaSessionManager); } @Override @@ -124,9 +145,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { if (intent == null) { return super.onStartCommand(intent, flags, startId); } - Log.d(TAG, "onStartCommand " + intent.getAction()); - mServiceLifecycle.startServiceWithIdleTimer(); AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { @@ -139,9 +158,17 @@ public int onStartCommand(Intent intent, int flags, int startId) { } } else if (Topic.TEMPLATE_RUNTIME.equals(message.topic)) { mTemplateruntimeHandler.handleAACSCommand(message); + } else if (Topic.MEDIA_PLAYBACK_REQUESTER.equalsIgnoreCase(message.topic)) { + mMediaSessionManager.handleMediaResumeResponse(message); + } else if (Topic.ALEXA_CLIENT.equalsIgnoreCase(message.topic)) { + mMediaSessionManager.connectionStatusChanged(message.payload); } }); + if (Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction()) && mMediaSessionManager != null) { + mMediaSessionManager.onMediaButtonIntentReceived(intent); + } + return super.onStartCommand(intent, flags, startId); } @@ -152,6 +179,8 @@ public void onDestroy() { mVASelectionSubscription.dispose(); if (mAuthSubscription != null) mAuthSubscription.dispose(); + if (mAACSConfigDisposable != null) + mAACSConfigDisposable.dispose(); mMediaSessionManager.deactivateMediaSession(); mMediaSessionManager.destroyMediaSession(); @@ -163,6 +192,7 @@ public void onDestroy() { } catch (Exception exception) { Log.e(TAG, "Error closing the Media Player Handler"); } + mShutdownActionReceiver.onDestroy(); } @Override @@ -175,18 +205,16 @@ public void onLoadChildren( @NonNull final String parentMediaId, @NonNull final Result> result) { List mediaItems = new ArrayList<>(); - MediaDescriptionCompat desc = - new MediaDescriptionCompat.Builder() - .setMediaId(MEDIA_ID) - .setTitle(getString(R.string.app_name)) - .setSubtitle(getString(R.string.alexa_music_hint_1)) - .setIconUri(Uri.parse("android.resource://" + - getPackageName() + "/" + "drawable/media_item_place_holder")) - .build(); + MediaDescriptionCompat desc = new MediaDescriptionCompat.Builder() + .setMediaId(MEDIA_ID) + .setTitle(getString(R.string.app_name)) + .setSubtitle(getString(R.string.alexa_music_hint_1)) + .setIconUri(Uri.parse("android.resource://" + getPackageName() + "/" + + "drawable/media_item_place_holder")) + .build(); MediaBrowserCompat.MediaItem songList = - new MediaBrowserCompat.MediaItem(desc, - MediaBrowserCompat.MediaItem.FLAG_BROWSABLE); + new MediaBrowserCompat.MediaItem(desc, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE); mediaItems.add(songList); result.sendResult(mediaItems); } @@ -213,7 +241,7 @@ private void handleLifecycleForMediaState(MediaState currentState) { * requires it. */ private void startAlexaMediaService() { - Log.i(TAG, "Starting Alexa Media Service (in foreground when required"); + Log.i(TAG, "Starting Alexa Media Service (in foreground when required)"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { Notification notification = mNotificationController.createServiceStartNotification(getApplicationContext()); startForeground(NotificationController.ALEXA_MEDIA_NOTIFICATION_ID, notification); @@ -260,7 +288,7 @@ void initializeMediaSessionWithErrorForGuidingUser() { app = AlexaApp.from(this); } catch (ClassCastException exception) { // This application doesn't provide AlexaApp. Ignore the auth state altogether. - Log.i(TAG, "AlexaApp not found. Will show hint that "); + Log.d(TAG, "AlexaApp not found. Will show hint that "); mMediaSessionManager.setMediaSessionError( PlaybackStateCompat.ERROR_CODE_UNKNOWN_ERROR, getString(R.string.alexa_music_hint_1), null, null); return; @@ -278,13 +306,16 @@ void initializeMediaSessionWithErrorForGuidingUser() { mVASelectionSubscription = null; } - // We want to make sure Alexa has been selected as default voice assist - Intent loginIntent = setupController.createIntentForLaunchingVoiceAssistantSwitchUI(); - PendingIntent pendingIntent = - PendingIntent.getActivity(this, 0, loginIntent, PendingIntent.FLAG_UPDATE_CURRENT); - mMediaSessionManager.setMediaSessionError(PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED, - getString(R.string.alexa_music_login_required), getString(R.string.alexa_music_login_text), - pendingIntent); + if (!mMediaSessionManager.mayAutoResume()) { + // We want to make sure Alexa has been selected as default voice assist + Intent loginIntent = setupController.createIntentForLaunchingVoiceAssistantSwitchUI(); + PendingIntent pendingIntent = + PendingIntent.getActivity(this, 0, loginIntent, PendingIntent.FLAG_UPDATE_CURRENT); + Log.d(TAG, "authStatus changed " + authStatus.getLoggedIn()); + mMediaSessionManager.setMediaSessionError(PlaybackStateCompat.ERROR_CODE_AUTHENTICATION_EXPIRED, + getString(R.string.alexa_music_login_required), getString(R.string.alexa_music_login_text), + pendingIntent); + } } else { observeVoiceAssistantSelectionToSetMediaSessionState(setupController); } @@ -337,6 +368,29 @@ public void onPlayerError(ExoPlaybackException error) { } } + /** + * Read config to check if Media Resume supported + * + * @param configs AACS configs. + */ + private void checkMediaResume(@NonNull String configs) { + boolean mediaResumeSupported = false; + try { + JSONObject config = new JSONObject(configs); + if (config.getJSONObject(AACS_ALEXA).has(REQUEST_MEDIA_PLAYBACK)) { + mediaResumeSupported = config.getJSONObject(AACS_ALEXA) + .getJSONObject(REQUEST_MEDIA_PLAYBACK) + .has(MEDIA_RESUME_THRESHOLD); + } + } catch (JSONException e) { + Log.w(TAG, "Failed to parse Media Resume config" + e.getMessage()); + } + Log.d(TAG, mediaResumeSupported ? "Media Resume supported" : "Media Resume not supported"); + mAACSConfigDisposable.dispose(); + mAACSConfigDisposable = null; + mMediaSessionManager.mediaResumeSupported(mediaResumeSupported); + } + /** * Manages service lifecycle and schedule start/stop of the service based * on the signal it receives from outer class. @@ -427,4 +481,4 @@ public void run() { mServiceStarted = false; } } -} \ No newline at end of file +} diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/content/AlbumArtContentProvider.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/content/AlbumArtContentProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/content/AlbumArtContentProvider.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/content/AlbumArtContentProvider.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AACSModule.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AACSModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AACSModule.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AACSModule.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java similarity index 79% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java index 641d96b42..34fa5c36d 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/AndroidModule.java @@ -1,11 +1,13 @@ package com.amazon.alexa.auto.media.dependencies; import android.content.Context; +import android.content.SharedPreferences; import android.support.v4.media.session.MediaSessionCompat; import androidx.annotation.NonNull; import com.amazon.alexa.auto.media.MusicStreamAttributeUpdater; +import com.amazon.alexa.auto.media.ShutdownActionReceiver; import com.amazon.alexa.auto.media.player.NotificationController; import java.lang.ref.WeakReference; @@ -21,6 +23,7 @@ @Module public class AndroidModule { private WeakReference mContext; + private static final String MEDIA_STATE_KEY = "MEDIA_STATE_KEY"; /** * Constructs the @c AndroidModule. @@ -82,4 +85,17 @@ public NotificationController provideNotificationController() { public MusicStreamAttributeUpdater provideMusicStreamUpdater() { return new MusicStreamAttributeUpdater(mContext); } + + @Provides + @Singleton + public SharedPreferences provideSharedPreferences() { + Context context = this.mContext.get(); + return context.getSharedPreferences(MEDIA_STATE_KEY, Context.MODE_PRIVATE); + } + + @Provides + @Singleton + public ShutdownActionReceiver provideShutdownObserver() { + return new ShutdownActionReceiver(mContext); + } } diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaComponent.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaComponent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaComponent.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaComponent.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java similarity index 89% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java index a64e696bb..3f4247f09 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/dependencies/MediaModule.java @@ -1,6 +1,8 @@ package com.amazon.alexa.auto.media.dependencies; import android.content.Context; +import android.content.SharedPreferences; +import android.media.AudioManager; import android.support.v4.media.session.MediaSessionCompat; import com.amazon.aacsconstants.PlaybackConstants; @@ -38,13 +40,15 @@ public class MediaModule { @Provides @Singleton public MediaSessionManager provideMediaSessionComponents(WeakReference context, MediaPlayerExo mediaPlayer, - MediaSessionCompat mediaSession, PlaybackControlMessages messageSender) { + MediaSessionCompat mediaSession, PlaybackControlMessages messageSender, + SharedPreferences sharedPreferences) { Context contextStrong = context.get(); Preconditions.checkNotNull(contextStrong); + AudioManager audioManager = (AudioManager) context.get().getSystemService(Context.AUDIO_SERVICE); return new MediaSessionManager(mediaPlayer, mediaSession, new MediaMetadataProvider(Glide.with(contextStrong), context), new PlaybackController(messageSender), - new CustomActionProviders(contextStrong, messageSender)); + new CustomActionProviders(contextStrong, messageSender), sharedPreferences, audioManager); } /** diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java similarity index 90% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java index 0b79e1e74..c1cd94eb3 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusController.java @@ -12,6 +12,7 @@ import androidx.annotation.VisibleForTesting; import com.amazon.alexa.auto.apps.common.util.Preconditions; +import com.amazon.alexa.auto.media.aacs.handlers.IMediaDuckingObserver; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -96,12 +97,15 @@ public interface PlaybackController { // Internal Dependencies. @NonNull - private final AudioFocusRequest mFocusRequest; + private AudioFocusRequest mFocusRequest; // State. @AudioFocusState private int mCurrentState; + private boolean mMayDuck; + private IMediaDuckingObserver mMediaDuckingObserver; + /** * Construct an instance of {@link MediaPlayerAudioFocusController}. * @@ -110,9 +114,6 @@ public interface PlaybackController { */ public MediaPlayerAudioFocusController(@NonNull AudioManager audioManager) { mAudioManager = audioManager; - - mFocusRequest = makeAudioFocusRequest(); - mCurrentState = AUDIO_FOCUS_STATE_NONE; } @@ -126,9 +127,6 @@ public void onAudioFocusChange(int focusChange) { case AudioManager.AUDIOFOCUS_GAIN: Preconditions.checkArgument(mCurrentState != AUDIO_FOCUS_STATE_NONE); switch (mCurrentState) { - case AUDIO_FOCUS_STATE_DUCKED: - mPlaybackController.adjustPlaybackVolume(VOLUME_MULTIPLIER_NORMAL); - break; case AUDIO_FOCUS_STATE_WAITING_FOR_ACQUISITION: mPlaybackController.startPlaybackNow(); break; @@ -152,8 +150,7 @@ public void onAudioFocusChange(int focusChange) { mPlaybackController.requestPausePlayback(); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: - mCurrentState = AUDIO_FOCUS_STATE_DUCKED; - mPlaybackController.adjustPlaybackVolume(VOLUME_MULTIPLIER_DUCK); + // Since AudioFocus request has setWillPauseWhenDucked false break; case AudioManager.AUDIOFOCUS_NONE: mPlaybackController.requestStopPlayback(); @@ -162,6 +159,28 @@ public void onAudioFocusChange(int focusChange) { } } + public void startDucking() { + mPlaybackController.adjustPlaybackVolume(VOLUME_MULTIPLIER_DUCK); + } + + private void startClientsideDucking() { + mPlaybackController.adjustPlaybackVolume(VOLUME_MULTIPLIER_DUCK); + if (mMediaDuckingObserver != null) { + mMediaDuckingObserver.reportClientDuckingState(true); + } + } + + public void stopDucking() { + mPlaybackController.adjustPlaybackVolume(VOLUME_MULTIPLIER_NORMAL); + } + + private void stopClientsideDucking() { + mPlaybackController.adjustPlaybackVolume(VOLUME_MULTIPLIER_NORMAL); + if (mMediaDuckingObserver != null) { + mMediaDuckingObserver.reportClientDuckingState(false); + } + } + @Override public void close() throws Exception { Log.i(TAG, "Disposing the Audio Focus Controller"); @@ -177,6 +196,10 @@ public void setPlaybackController(@NonNull PlaybackController controller) { mPlaybackController = controller; } + public void resetAudioFocusRequest() { + mFocusRequest = makeAudioFocusRequest(); + } + /** * Start the playback after acquiring the audio focus. * @@ -223,6 +246,11 @@ public void startPlaybackAfterAcquiringFocus() { } } + public void setMixability(boolean mayDuck, IMediaDuckingObserver audioPlayerHandler) { + this.mMayDuck = mayDuck; + mMediaDuckingObserver = audioPlayerHandler; + } + /** * Abandon the audio focus if we have acquired one. */ diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java similarity index 98% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java index 000042f28..75c9a1372 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaPlayerExo.java @@ -87,7 +87,8 @@ public void prepare(Uri uri) throws Exception { MediaSource mediaSource = mMediaSourceFactory.createHttpMediaSource(uri); Log.d(TAG, "mediaSource " + mediaSource.toString()); - mMainPlayer.prepare(mediaSource); + mMainPlayer.setMediaSource(mediaSource); + mMainPlayer.prepare(); } /** diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaSourceFactory.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaSourceFactory.java new file mode 100644 index 000000000..c1e30521f --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaSourceFactory.java @@ -0,0 +1,149 @@ +package com.amazon.alexa.auto.media.player; + +import android.content.Context; +import android.net.Uri; +import android.os.Handler; +import android.util.Log; + +import androidx.annotation.Nullable; + +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.source.MediaSource; +import com.google.android.exoplayer2.source.MediaSourceEventListener; +import com.google.android.exoplayer2.source.ProgressiveMediaSource; +import com.google.android.exoplayer2.source.dash.DashMediaSource; +import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource; +import com.google.android.exoplayer2.source.hls.HlsMediaSource; +import com.google.android.exoplayer2.source.smoothstreaming.DefaultSsChunkSource; +import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; +import com.google.android.exoplayer2.upstream.DataSource; +import com.google.android.exoplayer2.upstream.DefaultHttpDataSource; +import com.google.android.exoplayer2.upstream.HttpDataSource; +import com.google.android.exoplayer2.util.Util; + +/** + * Factory class to get the media source based on the URI received from Alexa service + */ +public class MediaSourceFactory { + private static final String TAG = "MediaSourceFactory"; + private static final String USER_AGENT = "ShowcaseMediaUA"; + private static final int CONNECTION_TIMEOUT_MS = 8000; + private static final int READ_TIMEOUT_MS = 20000; + private final Context mContext; + private final Handler mMainHandler = new Handler(); + private final PlaylistParser mPlaylistParser = new PlaylistParser(); + private final MediaSourceListener mMediaSourceListener = new MediaSourceListener(); + private DataSource.Factory mOkHttpDataSourceFactory; + + public MediaSourceFactory(Context context) { + mContext = context; + mOkHttpDataSourceFactory = buildOkHttpDataSourceFactory(mContext); + } + + private HttpDataSource.Factory buildOkHttpDataSourceFactory(Context context) { + // Some streams may see a long response time to begin data transfer from server after + // connection. Use default 8 second connection timeout and increased 20 second read timeout + // to catch this case and avoid reattempts to connect that will continue to time out. + // May perceive long "dead time" in cases where data read takes a long time + return new DefaultHttpDataSource.Factory() + .setUserAgent(USER_AGENT) + .setConnectTimeoutMs(CONNECTION_TIMEOUT_MS) + .setReadTimeoutMs(READ_TIMEOUT_MS) + .setAllowCrossProtocolRedirects(true); + } + + public MediaSource createHttpMediaSource(final Uri uri) throws Exception { + return createMediaSource(uri, mOkHttpDataSourceFactory, mMediaSourceListener, mMainHandler, mPlaylistParser); + } + + private MediaSource createMediaSource(final Uri uri, final DataSource.Factory dataSourceFactory, + final MediaSourceEventListener mediaSourceListener, final Handler handler, + final PlaylistParser playlistParser) throws Exception { + MediaType type = MediaType.inferContentType(uri.getLastPathSegment()); + MediaItem mediaItem = MediaItem.fromUri(uri); + switch (type) { + case DASH: + Log.d(TAG, "dash"); + DashMediaSource dashMediaSource = new DashMediaSource + .Factory(new DefaultDashChunkSource.Factory(dataSourceFactory), dataSourceFactory) + .createMediaSource(mediaItem); + dashMediaSource.addEventListener(handler, mediaSourceListener); + return dashMediaSource; + case SMOOTH_STREAMING: + Log.d(TAG, "smooth streaming"); + SsMediaSource ssMediaSource = new SsMediaSource + .Factory(new DefaultSsChunkSource.Factory(dataSourceFactory), dataSourceFactory) + .createMediaSource(mediaItem); + ssMediaSource.addEventListener(handler, mediaSourceListener); + return ssMediaSource; + case HLS: + Log.d(TAG, "hls"); + HlsMediaSource hlsMediaSource = new HlsMediaSource + .Factory(dataSourceFactory) + .createMediaSource(mediaItem); + hlsMediaSource.addEventListener(handler, mediaSourceListener); + return hlsMediaSource; + case M3U: + case PLS: + Log.d(TAG, "pls m3"); + Uri parsedUri = playlistParser.parseUri(uri); + return createMediaSource(parsedUri, dataSourceFactory, mediaSourceListener, handler, playlistParser); + case OTHER: + Log.d(TAG, "other"); + ProgressiveMediaSource progressiveMediaSource = new ProgressiveMediaSource + .Factory(dataSourceFactory) + .createMediaSource(mediaItem); + progressiveMediaSource.addEventListener(handler, mediaSourceListener); + return progressiveMediaSource; + default: + throw new IllegalStateException("Unsupported type"); + } + } + + /** + * Media types for creating an ExoPlayer MediaSource + **/ + enum MediaType { + DASH(C.TYPE_DASH), + SMOOTH_STREAMING(C.TYPE_SS), + HLS(C.TYPE_HLS), + OTHER(C.TYPE_OTHER), + M3U(4), + PLS(5); + + private final int mType; + + MediaType(int type) { + mType = type; + } + + public int getType() { + return mType; + } + + public static MediaType inferContentType(@Nullable final String fileExtension) { + if (fileExtension == null) { + return OTHER; + } else if (fileExtension.endsWith(".ashx") || fileExtension.endsWith(".m3u")) { + return M3U; + } else if (fileExtension.endsWith(".pls")) { + return PLS; + } else { + int type = Util.inferContentType(fileExtension); + for (MediaType mediaType : MediaType.values()) { + if (mediaType.getType() == type) + return mediaType; + } + return OTHER; + } + } + } + + /** + * Media Source event listener + **/ + private static class MediaSourceListener implements MediaSourceEventListener { + // TODO: Listen for errors and let the AACS know of those errors. + } +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaState.kt b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaState.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaState.kt rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/MediaState.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java similarity index 94% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java index c31f92dc0..4626cebf2 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/NotificationController.java @@ -38,12 +38,11 @@ public Notification createServiceStartNotification(@NonNull Context context) { NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context, ALEXA_MEDIA_CHANNEL_ID) .setChannelId(ALEXA_MEDIA_CHANNEL_ID) - .setSmallIcon(R.drawable.alexa_placeholder_logo) // your app icon - .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL) // your app icon + .setSmallIcon(R.drawable.alexa_bubble_small) + .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL) .setContentTitle(context.getString(R.string.notification_service_title)) //.setAutoCancel(true).setContentIntent(pendingIntent) .setNumber(1) - .setColor(255) //.setContentText(extras.get("nm").toString()) .setWhen(System.currentTimeMillis()); diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/PlaylistParser.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/PlaylistParser.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/PlaylistParser.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/player/PlaylistParser.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProvider.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProvider.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProvider.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProviders.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProviders.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProviders.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/CustomActionProviders.java diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java similarity index 95% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java index 06f429f86..751261173 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaMetadataProvider.java @@ -374,20 +374,22 @@ private Optional getMediaSourceProviderImageUrl(@NonNull RenderPlayerInf private static Optional getRatingObject(@NonNull RenderPlayerInfo metadata) { boolean thumbsUp = false, thumbsDown = false; boolean thumbsUpSelected = false, thumbsDownSelected = false; - for (PlaybackControl control : metadata.getPayload().getControls()) { - switch (control.getName()) { - case TemplateRuntimeConstants.CONTROL_NAME_THUMBS_UP: - if (control.getEnabled()) { - thumbsUp = true; - thumbsUpSelected = control.getSelected(); - } - break; - case TemplateRuntimeConstants.CONTROL_NAME_THUMBS_DOWN: - if (control.getEnabled()) { - thumbsDown = true; - thumbsDownSelected = control.getSelected(); - } - break; + if (metadata.getPayload().getControls() != null) { + for (PlaybackControl control : metadata.getPayload().getControls()) { + switch (control.getName()) { + case TemplateRuntimeConstants.CONTROL_NAME_THUMBS_UP: + if (control.getEnabled()) { + thumbsUp = true; + thumbsUpSelected = control.getSelected(); + } + break; + case TemplateRuntimeConstants.CONTROL_NAME_THUMBS_DOWN: + if (control.getEnabled()) { + thumbsDown = true; + thumbsDownSelected = control.getSelected(); + } + break; + } } } @@ -401,6 +403,7 @@ private static Optional getRatingObject(@NonNull RenderPlayerInfo } } + Log.w(TAG, "Playback control data is null, skip to build rating object."); return Optional.empty(); } diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaSessionManager.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaSessionManager.java new file mode 100644 index 000000000..be0b2700d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/MediaSessionManager.java @@ -0,0 +1,792 @@ +package com.amazon.alexa.auto.media.session; + +import android.app.PendingIntent; +import android.content.Intent; +import android.content.SharedPreferences; +import android.media.AudioAttributes; +import android.media.AudioFocusRequest; +import android.media.AudioManager; +import android.media.session.PlaybackState; +import android.os.Bundle; +import android.os.SystemClock; +import android.support.v4.media.RatingCompat; +import android.support.v4.media.session.MediaSessionCompat; +import android.support.v4.media.session.PlaybackStateCompat; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.media.session.MediaButtonReceiver; + +import com.amazon.aacsconstants.AASBConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.TemplateRuntimeConstants; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.PlaybackControl; +import com.amazon.alexa.auto.aacs.common.RenderPlayerInfo; +import com.amazon.alexa.auto.apps.common.util.Preconditions; +import com.amazon.alexa.auto.media.R; +import com.amazon.alexa.auto.media.player.MediaPlayerExo; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.ExoPlaybackException; +import com.google.android.exoplayer2.PlaybackParameters; +import com.google.android.exoplayer2.Player; +import com.google.android.exoplayer2.util.Log; +import com.google.android.exoplayer2.util.RepeatModeUtil; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import io.reactivex.rxjava3.disposables.Disposable; + +/** + * Central component to tie in the {@link android.media.session.MediaSession} with current + * media playback. + * The class is responsible for managing the media session from media content provider + * side. Following are some of those details: + *
    + *
  • + * Publishes the current playback state and media controls available (including custom + * controls) to Media Session. + *
  • + *
  • + * Coordinates with {@link MediaMetadataProvider} to compute the metadata + * and publishes the metadata into Media Session. + *
  • + *
  • + * Listen for Media Session callbacks (such as pause, play, seek, skip next etc.) + * and use the {@link PlaybackController} to carry out these tasks. + *
  • + *
+ */ +public class MediaSessionManager { + private static final String TAG = MediaSessionManager.class.getSimpleName(); + + // Fast Forward jump + public static final int FAST_FORWARD_MS = 30000; + // Rewind jump + public static final int REWIND_MS = FAST_FORWARD_MS; + + // Constant Strings used + private static final String LAST_PLAYBACK_STATE = "LAST_PLAYBACK_STATE"; + private static final String MEDIA_RESUME_SUPPORT = "MEDIA_RESUME_SUPPORT"; + private static final String FAILED_CAN_RETRY = "FAILED_CAN_RETRY"; + private static final String ERROR = "ERROR"; + private static final String FAILED_TIMEOUT = "FAILED_TIMEOUT"; + private static final String MEDIA_PLAYBACK_REQUEST_STATUS = "mediaPlaybackRequestStatus"; + private static final String STATUS = "status"; + + @NonNull + private final MediaPlayerExo mMediaPlayer; + @NonNull + private final MediaSessionCompat mMediaSession; + @NonNull + private final MediaMetadataProvider mMetadataProvider; + @NonNull + private final PlaybackController mControlDispatcher; + @NonNull + private final CustomActionProviders mCustomActionProviders; + @NotNull + private final SharedPreferences mSharedPreferences; + + // Map of custom action name and action object. + @NonNull + private final Map mCustomActions; + + @NonNull + private final MediaPlayerEventListener mMediaEventListener; + @NonNull + private final MediaSessionCallbackHandler mMediaSessionCallback; + + // Last Updated Render Player Info + @Nullable + RenderPlayerInfo mLastRenderPlayerInfo; + + // Subscriptions. + private Disposable mMetadataUpdateSubscription; + + // Shutdown state + boolean isDeviceShuttingDown = false; + + // Media resume retry variables. + private final ExecutorService executor; + private boolean mMediaResumeSupported; + private int reattempts = 10; + private boolean isConnected = false; + private boolean isMediaResumePending = false; + + // App Focus Management for Media Resume + private AudioManager mAudioManager; + private AudioFocusRequest mAudioFocusRequest; + boolean isAppFocused; + + /** + * Construct an instance of @c MediaSessionManager. + * + * @param mediaPlayer Media Player. + * @param mediaSession Media session + * @param metadataProvider Metadata for currently played media content. + * @param controlDispatcher Control commands handler. + * @param actionProviders Custom action providers. + */ + public MediaSessionManager(@NonNull MediaPlayerExo mediaPlayer, @NonNull MediaSessionCompat mediaSession, + @NonNull MediaMetadataProvider metadataProvider, @NonNull PlaybackController controlDispatcher, + @NonNull CustomActionProviders actionProviders, @NonNull SharedPreferences sharedPreferences, + @NotNull AudioManager audioManager) { + this.mMediaPlayer = mediaPlayer; + this.mMediaSession = mediaSession; + this.mMetadataProvider = metadataProvider; + this.mControlDispatcher = controlDispatcher; + this.mCustomActionProviders = actionProviders; + this.mSharedPreferences = sharedPreferences; + + this.mCustomActions = new HashMap<>(); + + this.mMediaEventListener = new MediaPlayerEventListener(); + this.mMediaSessionCallback = new MediaSessionCallbackHandler(); + this.mAudioManager = audioManager; + + executor = Executors.newSingleThreadExecutor(); + initAppFocusManager(); + } + + /** + * Media Resume starts its cycle when {@link MediaSessionCallbackHandler.onPlay()} is received + * by the platform. This class request AudioFocus if Media Resume is expected. If Audio focus + * is lost before Alexa gets connected and request media resume, this class assumes that + * some other audio is playing and drops the plan of requesting media resume + */ + private void initAppFocusManager() { + AudioAttributes mAudioAttributes = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_MEDIA) + .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) + .build(); + + AppFocusManager mAppFocusManager = new AppFocusManager(); + + mAudioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN) + .setAudioAttributes(mAudioAttributes) + .setWillPauseWhenDucked(false) + .setOnAudioFocusChangeListener(mAppFocusManager) + .build(); + } + + /** + * Fetch the media session managed by this manager. + * + * @return Media Session. + */ + @NonNull + public MediaSessionCompat getMediaSession() { + return mMediaSession; + } + + /** + * This method needs to be called on the reboot if media resume is expected. + * It ensures that Automotive Android calls onPlay() if Alexa Media is last playing active media app + */ + public void setupMediaResume() { + if (mayAutoResume()) { + setPlaybackStatePaused(); + } + } + + /** + * Activate the media session. + */ + public void activateMediaSession() { + if (!mMediaSession.isActive()) { + mMediaSession.setActive(true); + } + } + + public void setupMediaSessionCallbacks() { + Log.d(TAG, "setupMediaSessionCallbacks"); + mMediaSession.setCallback(mMediaSessionCallback); + mMediaPlayer.getPlayer().addListener(mMediaEventListener); + } + + /** + * Deactivate the media session. + */ + public void deactivateMediaSession() { + if (!isDeviceShuttingDown) { + mMediaSession.setActive(false); + mMediaSession.setCallback(null); + } + mMediaPlayer.getPlayer().removeListener(mMediaEventListener); + } + + /** + * Destroy the media session. + */ + public void destroyMediaSession() { + if (!isDeviceShuttingDown) { + getMediaSession().release(); + } + } + + /** + * Set the media session to error state. + * + * @param errorCode Error code (must be one of the PlaybackStateCompat.ERROR_CODE_XYZ). + * @param errorStr Error description. + * @param resolutionStr If there is a resolution of error, then the text which will + * appear on resolution button in the UI. + * @param resolutionIntent If there is a resolution of error, then pending intent that + * is invoked when resolution button in the UI is clicked. + */ + public void setMediaSessionError(int errorCode, @NonNull String errorStr, @Nullable String resolutionStr, + @Nullable PendingIntent resolutionIntent) { + Log.i(TAG, "Setting media session error with code:" + errorCode + " Error:" + errorStr); + + PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); + builder.setState(PlaybackStateCompat.STATE_ERROR, + 0, // Playback position. + 0.0f, // Playback speed. + SystemClock.elapsedRealtime()) + .setErrorMessage(errorCode, errorStr); + + if (resolutionStr != null && resolutionIntent != null) { + Bundle extras = new Bundle(); + extras.putString("android.media.extras.ERROR_RESOLUTION_ACTION_LABEL", resolutionStr); + extras.putParcelable("android.media.extras.ERROR_RESOLUTION_ACTION_INTENT", resolutionIntent); + builder.setExtras(extras); + } + activateMediaSession(); + Log.d(TAG, "setPlaybackState error"); + mMediaSession.setPlaybackState(builder.build()); + } + + /** + * Update the media session based on @c RenderPlayerInfo. + * + * @param renderPlayerInfo Render Player Info. + */ + public void updateMediaSession(@Nullable RenderPlayerInfo renderPlayerInfo) { + mLastRenderPlayerInfo = renderPlayerInfo; + updateShuffleRepeatMode(); + updateCustomActions(); + updatePlaybackState(); + updateMediaMetadata(); + } + + /** + * Update the Repeat and Shuffle Mode based on the last render player info. + */ + private void updateShuffleRepeatMode() { + mMediaSession.setShuffleMode(PlaybackStateCompat.SHUFFLE_MODE_INVALID); + mMediaSession.setRepeatMode(PlaybackStateCompat.REPEAT_MODE_INVALID); + + if (mLastRenderPlayerInfo == null) { + return; + } + + PlaybackControl shuffleControl = + mLastRenderPlayerInfo.getControl(TemplateRuntimeConstants.CONTROL_NAME_SHUFFLE); + PlaybackControl repeatControl = mLastRenderPlayerInfo.getControl(TemplateRuntimeConstants.CONTROL_NAME_LOOP); + + if (shuffleControl != null && shuffleControl.getEnabled()) { + mMediaSession.setShuffleMode(shuffleControl.getSelected() ? PlaybackStateCompat.SHUFFLE_MODE_ALL + : PlaybackStateCompat.SHUFFLE_MODE_NONE); + } + + if (repeatControl != null && repeatControl.getEnabled()) { + mMediaSession.setRepeatMode(repeatControl.getSelected() ? PlaybackStateCompat.REPEAT_MODE_ALL + : PlaybackStateCompat.REPEAT_MODE_NONE); + } + } + + /** + * Updates the custom actions for Media Session based on the last render player info. + */ + private void updateCustomActions() { + mCustomActions.clear(); + + if (mLastRenderPlayerInfo == null) { + return; + } + + List providers = + mCustomActionProviders.computeCustomActionProviders(mLastRenderPlayerInfo); + for (CustomActionProvider provider : providers) { + mCustomActions.put(provider.getCustomAction().getAction(), provider); + } + } + + /** + * Update media metadata for Media Session based on the last render player info. + */ + private void updateMediaMetadata() { + if (mMetadataUpdateSubscription != null) { + mMetadataUpdateSubscription.dispose(); + } + + if (mLastRenderPlayerInfo == null) { + mMediaSession.setMetadata(null); + return; + } + + mMetadataUpdateSubscription = + mMetadataProvider.updateMetadata(mLastRenderPlayerInfo).subscribe(metadataOptional -> { + metadataOptional.ifPresent(mMediaSession::setMetadata); + }); + } + + /** + * Updates media session playback state based on the last render player info. + */ + public final void updatePlaybackState() { + if (isDeviceShuttingDown) { + Log.d(TAG, "Ignore updatePlaybackState"); + return; + } + PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); + + int playbackState = 0; + ExoPlaybackException exoError = mMediaPlayer.getPlayer().getPlaybackError(); + if (exoError != null) { + playbackState = PlaybackStateCompat.STATE_ERROR; + // TODO: Add error string in media session. + } else { + playbackState = mMediaPlayer.getMediaState().toMediaSessionState(); + } + + if (playbackState == PlaybackStateCompat.STATE_PLAYING) { + activateMediaSession(); + } + + PlaybackParameters playbackParameters = mMediaPlayer.getPlayer().getPlaybackParameters(); + + builder.setActiveQueueItemId(MediaSessionCompat.QueueItem.UNKNOWN_ID) // until media browse + .setBufferedPosition(mMediaPlayer.getPlayer().getBufferedPosition()) + .setState(playbackState, mMediaPlayer.getPlayer().getCurrentPosition(), playbackParameters.speed, + SystemClock.elapsedRealtime()); + + if (mLastRenderPlayerInfo == null) { + mMediaSession.setPlaybackState(builder.build()); + return; + } + + for (CustomActionProvider actionProvider : mCustomActions.values()) { + PlaybackStateCompat.CustomAction action = actionProvider.getCustomAction(); + if (action != null) { + builder.addCustomAction(action); + } + } + + builder.setActions(computePlaybackActions(mLastRenderPlayerInfo)); + + PlaybackStateCompat playbackStateCompat = builder.build(); + mMediaSession.setPlaybackState(playbackStateCompat); + storePlaybackState(playbackStateCompat.getState()); + } + + private void storePlaybackState(int playbackState) { + if (playbackState == PlaybackStateCompat.STATE_ERROR) { + // We don't want to store the error state because this can not be resumable condition + return; + } + Log.d(TAG, String.format("storePlaybackState %d", playbackState)); + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putInt(LAST_PLAYBACK_STATE, playbackState); + editor.apply(); + } + + /** + * Computes the supported playback actions (for Media Session). + * + * @param playerInfo Render Player Info needed to compute the actions. + * @return Supported Media Session playback actions as flags. + */ + private static long computePlaybackActions(@NonNull RenderPlayerInfo playerInfo) { + long enabledActions = PlaybackStateCompat.ACTION_STOP; + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_SHUFFLE)) { + enabledActions |= PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_LOOP)) { + enabledActions |= PlaybackStateCompat.ACTION_SET_REPEAT_MODE; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_NEXT)) { + enabledActions |= PlaybackStateCompat.ACTION_SKIP_TO_NEXT; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_PREVIOUS)) { + enabledActions |= PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_SKIP_BACKWARD)) { + enabledActions |= PlaybackStateCompat.ACTION_REWIND; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_SKIP_FORWARD)) { + // Only when we can fast forward, do we allow to seek. + enabledActions |= PlaybackStateCompat.ACTION_FAST_FORWARD | PlaybackStateCompat.ACTION_SEEK_TO; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_PLAY_PAUSE)) { + enabledActions |= PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE; + } + + if (playerInfo.isControlEnabled(TemplateRuntimeConstants.CONTROL_NAME_THUMBS_UP)) { + enabledActions |= PlaybackStateCompat.ACTION_SET_RATING; + } + + return enabledActions; + } + + /** + * Tells if the playback action can be dispatched. It can only be dispatched + * if current playback state supports the given playback action. + * + * @param action Action to test. + * @return true if action can be dispatched. + */ + private boolean canDispatchPlaybackAction(long action) { + if (action == PlaybackStateCompat.ACTION_STOP) + return true; + + return mLastRenderPlayerInfo != null && (computePlaybackActions(mLastRenderPlayerInfo) & action) != 0; + } + + /** + * Seek the Media Player with given offset. + * + * @param offsetMs Offset in milliseconds, negative offset would rewind + * the playback. + */ + private void seekToOffset(long offsetMs) { + Player player = mMediaPlayer.getPlayer(); + long positionMs = player.getCurrentPosition() + offsetMs; + long durationMs = player.getDuration(); + if (durationMs != C.TIME_UNSET) { + positionMs = Math.min(positionMs, durationMs); + } + positionMs = Math.max(positionMs, 0); + mControlDispatcher.seekTo( + mMediaPlayer.getPlayer(), mMediaPlayer.getPlayer().getCurrentWindowIndex(), positionMs); + } + + public void onMediaButtonIntentReceived(Intent intent) { + MediaButtonReceiver.handleIntent(mMediaSession, intent); + } + + public boolean mayAutoResume() { + // Set it true by default for the very first time where config might be not read yet. + // Because of the '&&' this logic would not give unexpected result + mMediaResumeSupported = mSharedPreferences.getBoolean(MEDIA_RESUME_SUPPORT, true); + return mMediaResumeSupported + && PlaybackState.STATE_PLAYING + == mSharedPreferences.getInt(LAST_PLAYBACK_STATE, PlaybackState.STATE_NONE); + } + + /** + * If device is shutdown while playing the Alexa music, + * set the playback state pause after reboot. This provides automotive android a + * chance to resume the paused music. + */ + private void setPlaybackStatePaused() { + PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder(); + builder.setActiveQueueItemId(MediaSessionCompat.QueueItem.UNKNOWN_ID) // until media browse + .setState(PlaybackStateCompat.STATE_PAUSED, PlaybackState.PLAYBACK_POSITION_UNKNOWN, 1.0f, + SystemClock.elapsedRealtime()) + .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_FROM_MEDIA_ID); + Log.d(TAG, "setPlaybackState paused"); + mMediaSession.setPlaybackState(builder.build()); + } + + public void shutdown() { + Log.d(TAG, "device is shutting down"); + isDeviceShuttingDown = true; + } + + public void handleMediaResumeResponse(AACSMessage message) { + if (message.action.contains(Action.MediaPlaybackRequestor.MEDIA_PLAYBACK_RESPONSE)) { + try { + JSONObject messagePayload = new JSONObject(message.payload); + Log.i(TAG, messagePayload.toString()); + if (messagePayload.getString(MEDIA_PLAYBACK_REQUEST_STATUS).equals(FAILED_CAN_RETRY) + && reattempts > 0) { + executor.execute(new ExecuteMediaPlaybackRequest(1000)); + } else if (ERROR.equalsIgnoreCase(messagePayload.getString(MEDIA_PLAYBACK_REQUEST_STATUS)) + || FAILED_TIMEOUT.equalsIgnoreCase(messagePayload.getString(MEDIA_PLAYBACK_REQUEST_STATUS))) { + setMediaSessionError(PlaybackStateCompat.ERROR_CODE_UNKNOWN_ERROR, "", null, null); + abandonAudioFocus(); + } else { + abandonAudioFocus(); + } + } catch (Exception exception) { + Log.w(TAG, + String.format("Failed to parse Media resume response message: %s error: %s", message.payload, + exception.getMessage())); + } + } + } + + public void connectionStatusChanged(String payload) { + Preconditions.checkArgument(payload != null && !payload.isEmpty()); + Log.d(TAG, payload); + try { + JSONObject jsonPayload = new JSONObject(payload); + String status = jsonPayload.getString(STATUS); + if (status.equalsIgnoreCase(AASBConstants.AlexaClient.ALEXA_CLIENT_STATUS_CONNECTED)) { + isConnected = true; + handleAlexaConnected(); + } + } catch (Exception e) { + Log.e(TAG, "failed to get connectionStatusChanged"); + } + } + + private void handleAlexaConnected() { + if (isMediaResumePending) { + isMediaResumePending = false; + executor.execute(new ExecuteMediaPlaybackRequest(0)); + } else { + Log.w(TAG, "handleAlexaConnected resume request is not pending"); + abandonAudioFocus(); + } + } + + /** + * Set if media resume supported or not + * @param mediaResumeSupported + */ + public void mediaResumeSupported(boolean mediaResumeSupported) { + mMediaResumeSupported = mediaResumeSupported; + SharedPreferences.Editor editor = mSharedPreferences.edit(); + editor.putBoolean(MEDIA_RESUME_SUPPORT, mediaResumeSupported); + editor.apply(); + } + + /** + * Listener for Media Player Events. + */ + @VisibleForTesting + class MediaPlayerEventListener implements Player.EventListener { + @Override + public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + updatePlaybackState(); + } + + @Override + public void onPlayerError(ExoPlaybackException error) { + updatePlaybackState(); + } + + @Override + public void onIsPlayingChanged(boolean isPlaying) { + updatePlaybackState(); + } + } + + /** + * Handler for Media Session callbacks. + */ + @VisibleForTesting + class MediaSessionCallbackHandler extends MediaSessionCompat.Callback { + @Override + public void onPlay() { + Log.d(TAG, "onPlay isConnected:" + isConnected); + if (mayAutoResume() && mLastRenderPlayerInfo == null) { + if (isConnected) { + // Send Media Resume request + executor.execute(new ExecuteMediaPlaybackRequest(0)); + } else { + // Media Resume request will be sent after Alexa is authenticated and connected + isMediaResumePending = true; + } + + mMediaSession.setPlaybackState( + new PlaybackStateCompat.Builder() + .setActiveQueueItemId(MediaSessionCompat.QueueItem.UNKNOWN_ID) // until media browse + .setState(PlaybackStateCompat.STATE_BUFFERING, PlaybackState.PLAYBACK_POSITION_UNKNOWN, + 1.0f, SystemClock.elapsedRealtime()) + .setActions(PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE) + .build()); + requestAudioFocus(); + return; + } + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_PLAY)) { + mControlDispatcher.setPlay(true); + } + } + + @Override + public void onPause() { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_PAUSE)) { + mControlDispatcher.setPlay(false); + } + } + + @Override + public void onSeekTo(long positionMs) { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SEEK_TO)) { + mControlDispatcher.seekTo( + mMediaPlayer.getPlayer(), mMediaPlayer.getPlayer().getCurrentWindowIndex(), positionMs); + } + } + + @Override + public void onFastForward() { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_FAST_FORWARD)) { + if (mMediaPlayer.getPlayer().isCurrentWindowSeekable()) { + seekToOffset(FAST_FORWARD_MS); + } + } + } + + @Override + public void onRewind() { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_REWIND)) { + seekToOffset(-REWIND_MS); + } + } + + @Override + public void onStop() { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_STOP)) { + mControlDispatcher.stop(); + } + } + + @Override + public void onSetShuffleMode(@PlaybackStateCompat.ShuffleMode int shuffleMode) { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE)) { + boolean shuffleModeEnabled; + switch (shuffleMode) { + case PlaybackStateCompat.SHUFFLE_MODE_ALL: + case PlaybackStateCompat.SHUFFLE_MODE_GROUP: + shuffleModeEnabled = true; + break; + case PlaybackStateCompat.SHUFFLE_MODE_NONE: + case PlaybackStateCompat.SHUFFLE_MODE_INVALID: + default: + shuffleModeEnabled = false; + break; + } + mControlDispatcher.setShuffleModeEnabled(shuffleModeEnabled); + } + } + + @Override + public void onSetRepeatMode(@PlaybackStateCompat.RepeatMode int mediaSessionRepeatMode) { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SET_REPEAT_MODE)) { + @RepeatModeUtil.RepeatToggleModes + int repeatMode; + switch (mediaSessionRepeatMode) { + case PlaybackStateCompat.REPEAT_MODE_ALL: + case PlaybackStateCompat.REPEAT_MODE_GROUP: + repeatMode = Player.REPEAT_MODE_ALL; + break; + case PlaybackStateCompat.REPEAT_MODE_ONE: + repeatMode = Player.REPEAT_MODE_ONE; + break; + case PlaybackStateCompat.REPEAT_MODE_NONE: + case PlaybackStateCompat.REPEAT_MODE_INVALID: + default: + repeatMode = Player.REPEAT_MODE_OFF; + break; + } + mControlDispatcher.setRepeatMode(repeatMode); + } + } + + @Override + public void onSkipToNext() { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SKIP_TO_NEXT)) { + mControlDispatcher.skipToNext(); + } + } + + @Override + public void onSkipToPrevious() { + if (canDispatchPlaybackAction(PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)) { + mControlDispatcher.skipToPrevious(); + } + } + + @Override + public void onCustomAction(String action, @Nullable Bundle extras) { + CustomActionProvider actionProvider = mCustomActions.get(action); + if (actionProvider != null) { + actionProvider.onCustomAction(action, extras); + } + } + + @Override + public void onSetRating(RatingCompat rating) { + mControlDispatcher.setRating(rating); + } + + @Override + public void onSetRating(RatingCompat rating, @Nullable Bundle extras) { + mControlDispatcher.setRating(rating); + } + + @Override + public boolean onMediaButtonEvent(Intent mediaButtonEvent) { + Log.d(TAG, "onMediaButtonEvent"); + onMediaButtonIntentReceived(mediaButtonEvent); + return true; + } + } + + private class ExecuteMediaPlaybackRequest implements Runnable { + int delayMs; + { delayMs = 0; } + + private ExecuteMediaPlaybackRequest(int delay) { + delayMs = delay; + } + + @Override + public void run() { + if (delayMs > 0) { + try { + Thread.sleep(delayMs); + } catch (InterruptedException e) { + } + } + Log.d(TAG, "Retrying for media resume"); + mControlDispatcher.requestMediaPlayback(); + reattempts--; + } + } + + // This code is to handle a case where auto resuming a media can be cancelled if driver plays + // any other audio before the media resumes + private void requestAudioFocus() { + if (mAudioManager.requestAudioFocus(mAudioFocusRequest) == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + isAppFocused = true; + } + } + + private void abandonAudioFocus() { + if (isAppFocused + && mAudioManager.abandonAudioFocusRequest(mAudioFocusRequest) + == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { + isAppFocused = false; + } + } + + private class AppFocusManager implements AudioManager.OnAudioFocusChangeListener { + @Override + public void onAudioFocusChange(int focusChange) { + if (focusChange == AudioManager.AUDIOFOCUS_LOSS || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT + || focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { + isMediaResumePending = false; + abandonAudioFocus(); + } + } + } +} diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProvider.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProvider.java rename to aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProvider.java diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackController.java b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackController.java new file mode 100644 index 000000000..facefc51c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/java/com/amazon/alexa/auto/media/session/PlaybackController.java @@ -0,0 +1,109 @@ +package com.amazon.alexa.auto.media.session; + +import static com.google.android.exoplayer2.Player.REPEAT_MODE_OFF; + +import android.support.v4.media.RatingCompat; + +import androidx.annotation.NonNull; + +import com.amazon.aacsconstants.PlaybackConstants; +import com.amazon.alexa.auto.aacs.common.PlaybackControlMessages; +import com.google.android.exoplayer2.Player; + +/** + * Playback controller to implement playback commands such as play/pause/seek + * etc. + */ +public class PlaybackController { + @NonNull + private final PlaybackControlMessages mMessageSender; + + /** + * Construct an instance of @c ControlDispatcherImpl. + * + * @param sender Message sender for playback control. + */ + public PlaybackController(@NonNull PlaybackControlMessages sender) { + this.mMessageSender = sender; + } + + /** + * Call this method to play/pause the media. + * + * @param play true for playing the media, false for pausing it. + */ + public void setPlay(boolean play) { + mMessageSender.sendButtonCommandToAACS( + play ? PlaybackConstants.PlaybackButton.PLAY : PlaybackConstants.PlaybackButton.PAUSE); + } + + /** + * Set repeat mode for the playback. + * + * @param repeatMode Repeat mode. + */ + public void setRepeatMode(@Player.RepeatMode int repeatMode) { + mMessageSender.sendToggleCommandToAACS(PlaybackConstants.ToggleButton.REPEAT, repeatMode != REPEAT_MODE_OFF); + } + + /** + * Enable/Disable shuffle mode for the playback. + * + * @param shuffleModeEnabled Whether to enable/disable shuffle mode. + */ + public void setShuffleModeEnabled(boolean shuffleModeEnabled) { + mMessageSender.sendToggleCommandToAACS(PlaybackConstants.ToggleButton.SHUFFLE, shuffleModeEnabled); + } + + /** + * Stop the playback. + */ + public void stop() { + mMessageSender.sendButtonCommandToAACS(PlaybackConstants.PlaybackButton.PAUSE); + } + + /** + * Skip to previous media item. + */ + public void skipToPrevious() { + mMessageSender.sendButtonCommandToAACS(PlaybackConstants.PlaybackButton.PREVIOUS); + } + + /** + * Skip to next media item. + */ + public void skipToNext() { + mMessageSender.sendButtonCommandToAACS(PlaybackConstants.PlaybackButton.NEXT); + } + + /** + * Set the rating for currently played media item. + * + * @param rating Rating to set. + */ + public void setRating(RatingCompat rating) { + if (rating.isRated()) { + mMessageSender.sendToggleCommandToAACS(rating.isThumbUp() ? PlaybackConstants.ToggleButton.THUMBS_UP + : PlaybackConstants.ToggleButton.THUMBS_DOWN, + true); + } else { + mMessageSender.sendToggleCommandToAACS(PlaybackConstants.ToggleButton.THUMBS_UP, false); + mMessageSender.sendToggleCommandToAACS(PlaybackConstants.ToggleButton.THUMBS_DOWN, false); + } + } + + /** + * Seek to different position in the playback. + * + * @param player Player object where seek will be applied. + * @param windowIndex Window index for seek. + * @param positionMs Position in milliseconds. + */ + public void seekTo(Player player, int windowIndex, long positionMs) { + player.seekTo(windowIndex, positionMs); + } + + public void requestMediaPlayback() { + mMessageSender.sendRequestMediaPlaybackToAACS(); + } +} diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/default_album_image.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/default_album_image.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/default_album_image.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/default_album_image.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike_selected.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike_selected.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike_selected.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_dislike_selected.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_item_place_holder.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_item_place_holder.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_item_place_holder.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_item_place_holder.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like_selected.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like_selected.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like_selected.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_like_selected.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat_selected.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat_selected.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat_selected.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_repeat_selected.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle_selected.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle_selected.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle_selected.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_shuffle_selected.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_backward_selected.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_backward_selected.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_backward_selected.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_backward_selected.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_forward_selected.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_forward_selected.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_forward_selected.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_forward_selected.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_next_disabled.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_next_disabled.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_next_disabled.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_next_disabled.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_previous_disabled.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_previous_disabled.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_previous_disabled.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/drawable/media_skip_previous_disabled.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/layout/msp_option_view.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/layout/msp_option_view.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/layout/msp_option_view.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/layout/msp_option_view.xml diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-de/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-de/strings.xml new file mode 100644 index 000000000..a86d2da50 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-de/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa-Musik + Alexa-Musik mit Mediensteuerung + Alexa-Musik + Vorwärts + Zurück + Daumen hoch + Daumen runter + Zufallswiedergabe + Endlosschleife + Weiter + Zurück + Bitte rufen Sie die Alexa-Einstellungen auf und melden Sie sich mit Amazon an, um Musik mit Alexa abzuspielen + Anmelden + Stellen Sie Alexa als Assistent-App ein, um Musik mit Alexa abzuspielen + Wählen Sie Alexa als Assistent-App aus + Versuchen Sie es mit: „Alexa, spiel Musik.“ +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rAU/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 000000000..dd6442c53 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + Alexa Music with Media Control + Alexa Music + Skip Forwards + Skip Backwards + Thumbs Up + Thumbs Down + Shuffle + Loop + Next + Previous + Please go to Alexa settings and log in with Amazon to play music with Alexa + Sign in + Change Assist App to Alexa to play music with Alexa + Select Alexa as Assist App + Try saying, \"Alexa, play music\". +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rCA/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rCA/strings.xml new file mode 100644 index 000000000..dd6442c53 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rCA/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + Alexa Music with Media Control + Alexa Music + Skip Forwards + Skip Backwards + Thumbs Up + Thumbs Down + Shuffle + Loop + Next + Previous + Please go to Alexa settings and log in with Amazon to play music with Alexa + Sign in + Change Assist App to Alexa to play music with Alexa + Select Alexa as Assist App + Try saying, \"Alexa, play music\". +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rIN/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 000000000..dd6442c53 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + Alexa Music with Media Control + Alexa Music + Skip Forwards + Skip Backwards + Thumbs Up + Thumbs Down + Shuffle + Loop + Next + Previous + Please go to Alexa settings and log in with Amazon to play music with Alexa + Sign in + Change Assist App to Alexa to play music with Alexa + Select Alexa as Assist App + Try saying, \"Alexa, play music\". +  |  + diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rUS/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en-rUS/strings.xml diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en/strings.xml new file mode 100644 index 000000000..dd6442c53 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-en/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + Alexa Music with Media Control + Alexa Music + Skip Forwards + Skip Backwards + Thumbs Up + Thumbs Down + Shuffle + Loop + Next + Previous + Please go to Alexa settings and log in with Amazon to play music with Alexa + Sign in + Change Assist App to Alexa to play music with Alexa + Select Alexa as Assist App + Try saying, \"Alexa, play music\". +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rMX/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 000000000..0b7df8508 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Música en Alexa + Música en Alexa con control de contenido multimedia + Música en Alexa + Avanzar + Retroceder + Me gusta + No me gusta + Reproducción aleatoria + Repetir + Siguiente + Anterior + Ve a la configuración de Alexa e inicia sesión con Amazon para reproducir música usando Alexa + Iniciar sesión + Cambia la app del asistente a Alexa para reproducir música con Alexa + Selecciona Alexa como la app del asistente + Prueba a decir: “Alexa, pon música”. +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rUS/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..0b7df8508 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Música en Alexa + Música en Alexa con control de contenido multimedia + Música en Alexa + Avanzar + Retroceder + Me gusta + No me gusta + Reproducción aleatoria + Repetir + Siguiente + Anterior + Ve a la configuración de Alexa e inicia sesión con Amazon para reproducir música usando Alexa + Iniciar sesión + Cambia la app del asistente a Alexa para reproducir música con Alexa + Selecciona Alexa como la app del asistente + Prueba a decir: “Alexa, pon música”. +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..db3a6f8a5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-es/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Música de Alexa + Música de Alexa con control multimedia + Música de Alexa + Avanzar + Retroceder + Me gusta + No me gusta + Reproducir aleatoriamente + Reproducir en modo repetición + Siguiente + Anterior + Ve a la configuración de Alexa e inicia sesión con Amazon para reproducir música con Alexa + Iniciar sesión + Establece Alexa como app de asistencia para reproducir música con Alexa + Seleccionar Alexa como app de asistencia + Prueba a decir: \"Alexa, pon la música\". +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr-rCA/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000..44ab44d55 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Musique + Alexa Musique avec contrôle des médias + Alexa Musique + Avance rapide + Revenir au précédent + J\'aime + Je n\'aime pas + Lecture aléatoire + Boucle + Suivant + Précédent + Veuillez accéder aux paramètres Alexa et vous connecter avec Amazon pour écouter de la musique avec Alexa + Se connecter + Passez de l\'application d\'assistance à Alexa pour écouter de la musique avec Alexa + Sélectionnez Alexa comme application d\'assistance + Essayez de dire : « Alexa, joue de la musique. » +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr/strings.xml new file mode 100644 index 000000000..bca79cb85 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-fr/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Musique Alexa + Musique Alexa avec contrôle multimédia + Musique Alexa + Avance rapide + Retour rapide + J\'aime + Je n\'aime pas + Lecture aléatoire + En boucle + Suivant + Précédent + Veuillez vous rendre dans les paramètres Alexa et vous connecter avec Amazon pour écouter de la musique avec Alexa + Se connecter + Changer votre application d\'assistance pour Alexa et écouter de la musique avec Alexa + Sélectionner Alexa comme application d\'assistance + Essayez de dire : « Alexa, joue de la musique. » +  |  + diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/dimens.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/dimens.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/dimens.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/styles.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/styles.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/styles.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/styles.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/values.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/values.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/values.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values-h600dp/values.xml diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-hi-rIN/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-hi-rIN/strings.xml new file mode 100644 index 000000000..8f6f691a9 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-hi-rIN/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + मीडिया कंट्रोल के साथ Alexa Music + Alexa Music + इसे छोड़कर आगे जाएं + इसे छोड़कर पीछे जाएं + पसंद है + नापसंद + शफ़ल करें + लूप करें + आगे + पीछे + कृपया Alexa की सेटिंग में जाएं और Alexa के ज़रिए म्यूज़िक चलाने के लिए, Amazon के साथ लॉग इन करें + साइन इन करें + Alexa के ज़रिए म्यूज़िक चलाने के लिए, असिस्ट ऐप को बदल कर Alexa चुनें + Alexa को असिस्ट ऐप के रूप में चुनें + ये बोलकर देखें, \"Alexa, म्यूज़िक चलाओ.\" +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-it/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-it/strings.xml new file mode 100644 index 000000000..0f44713dc --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-it/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + Alexa Music con controllo multimediale + Alexa Music + Vai avanti + Vai indietro + Pollice in su + Pollice in giù + Riproduzione casuale + Ripetizione + Avanti + Indietro + Vai alle impostazioni di Alexa e accedi con Amazon per riprodurre musica con Alexa + Accedi + Cambia l\'impostazione dell\'app di assistenza su Alexa per riprodurre musica con Alexa + Seleziona Alexa come applicazione di assistenza + Prova a dire: \"Alexa, metti della musica.\" +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-ja/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-ja/strings.xml new file mode 100644 index 000000000..b018722de --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-ja/strings.xml @@ -0,0 +1,21 @@ + + + Alexaメディア + Alexaミュージック + Alexaミュージック(メディアコントロール) + Alexaミュージック + 先へスキップ + 後ろへスキップ + サムズアップ + サムズダウン + シャッフル + ループ再生 + 次へ + 戻る + Alexaで音楽を再生するには、Alexaの設定画面で、Amazonにログインしてください。 + サインイン + Alexaで音楽を再生するには、アシスタントアプリをAlexaに変更してください + Alexaをアシスタントアプリとして選択 + 「アレクサ、音楽をかけて」と言ってみてください +  |  + diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-pt-rBR/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000..b916f0dd2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,21 @@ + + + Alexa Media + Alexa Music + Alexa Music com controle de mídia + Alexa Music + Próxima faixa + Faixa anterior + Sinal de positivo + Sinal de negativo + Ordem aleatória + Repetir + Avançar + Anterior + Acesse as configurações da Alexa e faça login com a Amazon para reproduzir músicas com a Alexa + Iniciar sessão + Altere o aplicativo de assistência para a Alexa para reproduzir músicas com a Alexa + Selecione a Alexa como aplicativo de assistência + Diga, \"Alexa, toque música.\" +  |  + diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values/colors.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/colors.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values/colors.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values/colors.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values/dimens.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values/dimens.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values/integers.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/integers.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values/integers.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values/integers.xml diff --git a/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/strings.xml new file mode 100644 index 000000000..ef82ee14f --- /dev/null +++ b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/strings.xml @@ -0,0 +1,23 @@ + + Alexa Media + Alexa Music + Alexa Music with Media Control + Alexa Music + + Skip Forward + Skip Backward + Thumbs Up + Thumbs Down + Shuffle + Loop + Next + Previous + + Please go to Alexa settings and login with Amazon to play music with Alexa + Sign in + Change Assist App to Alexa to play music with Alexa + Select Alexa as Assist App + Try saying, \"Alexa, play music.\" + +  |  + diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values/styles.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/styles.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values/styles.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values/styles.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/main/res/values/values.xml b/aacs/android/app-components/alexa-auto-media-player/src/main/res/values/values.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/main/res/values/values.xml rename to aacs/android/app-components/alexa-auto-media-player/src/main/res/values/values.xml diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseServiceTest.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseServiceTest.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseServiceTest.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/browse/AlexaMediaBrowseServiceTest.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusControllerTest.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusControllerTest.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusControllerTest.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/player/MediaPlayerAudioFocusControllerTest.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaMetadataProverTest.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaMetadataProverTest.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaMetadataProverTest.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaMetadataProverTest.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt similarity index 93% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt index ef19d5222..41d151bdd 100644 --- a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt +++ b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/MediaSessionManagerTest.kt @@ -1,18 +1,15 @@ package com.amazon.alexa.auto.media.session import android.content.Context +import android.content.SharedPreferences +import android.media.AudioManager import android.os.Build import android.support.v4.media.MediaMetadataCompat import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.PlaybackStateCompat import androidx.test.core.app.ApplicationProvider import com.amazon.aacsconstants.TemplateRuntimeConstants -import com.amazon.aacsconstants.TemplateRuntimeConstants.CONTROL_NAME_LOOP -import com.amazon.aacsconstants.TemplateRuntimeConstants.CONTROL_NAME_PLAY_PAUSE -import com.amazon.aacsconstants.TemplateRuntimeConstants.CONTROL_NAME_SHUFFLE -import com.amazon.aacsconstants.TemplateRuntimeConstants.CONTROL_NAME_SKIP_BACKWARD -import com.amazon.aacsconstants.TemplateRuntimeConstants.CONTROL_NAME_SKIP_FORWARD -import com.amazon.aacsconstants.TemplateRuntimeConstants.CONTROL_TYPE_BUTTON +import com.amazon.aacsconstants.TemplateRuntimeConstants.* import com.amazon.alexa.auto.aacs.common.PlaybackControl import com.amazon.alexa.auto.aacs.common.PlaybackControlMessages import com.amazon.alexa.auto.media.R @@ -26,21 +23,15 @@ import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.Captor -import org.mockito.Mock -import org.mockito.Mockito -import org.mockito.Mockito.`when` -import org.mockito.Mockito.any -import org.mockito.Mockito.anyBoolean -import org.mockito.Mockito.mock -import org.mockito.Mockito.times -import org.mockito.Mockito.verify -import org.mockito.MockitoAnnotations +import org.mockito.* +import org.mockito.ArgumentMatchers.anyInt +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito.* import org.robolectric.RobolectricTestRunner import org.robolectric.annotation.Config import java.util.* + @RunWith(RobolectricTestRunner::class) @Config(sdk = intArrayOf(Build.VERSION_CODES.O)) class MediaSessionManagerTest { @@ -55,6 +46,10 @@ class MediaSessionManagerTest { @Mock lateinit var mMockMessageSender: PlaybackControlMessages @Mock lateinit var mMockSkipForwardActionProvider: PlaybackControlButtonActionProvider @Mock lateinit var mMockSkipBackwardAcitonProvider: PlaybackControlButtonActionProvider + @Mock lateinit var mAudioManager : AudioManager + @Mock lateinit var mockContext: Context + @Mock lateinit var mockPrefs: SharedPreferences + @Mock lateinit var mockEditor: SharedPreferences.Editor // Argument capture @Captor private lateinit var mPlaybackCompatArgs: ArgumentCaptor @@ -66,6 +61,8 @@ class MediaSessionManagerTest { @Before fun setup() { MockitoAnnotations.openMocks(this) + `when`(mockContext!!.getSharedPreferences(anyString(), anyInt())).thenReturn(mockPrefs) + `when`(mockContext!!.getSharedPreferences(anyString(), anyInt()).edit()).thenReturn(mockEditor) mSkipForwardAction = PlaybackStateCompat.CustomAction.Builder( "skip-forward", "skip-forward", R.drawable.media_skip_forward_selected).build() @@ -90,7 +87,7 @@ class MediaSessionManagerTest { mClassUnderTest = MediaSessionManager( mMockMediaPlayer, mMockMediaSession, mMockMetadataProvder, - mMockController, mCustomActionProviders) + mMockController, mCustomActionProviders, mockPrefs, mAudioManager) } @Test @@ -298,6 +295,7 @@ class MediaSessionManagerTest { */ fun activateMediaSession() : Pair { mClassUnderTest.activateMediaSession() + mClassUnderTest.setupMediaSessionCallbacks() val mediaSessionCallbackArgs = ArgumentCaptor.forClass( MediaSessionCompat.Callback::class.java) @@ -308,4 +306,4 @@ class MediaSessionManagerTest { return Pair(mediaSessionCallbackArgs.value, playerListenerArgs.value) } -} \ No newline at end of file +} diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProviderTest.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProviderTest.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProviderTest.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControlButtonActionProviderTest.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControllerTest.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControllerTest.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControllerTest.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/PlaybackControllerTest.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/RenderPlayerInfoBuilder.kt b/aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/RenderPlayerInfoBuilder.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/RenderPlayerInfoBuilder.kt rename to aacs/android/app-components/alexa-auto-media-player/src/test/java/com/amazon/alexa/auto/media/session/RenderPlayerInfoBuilder.kt diff --git a/platforms/android/app-components/alexa-auto-media-player/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/aacs/android/app-components/alexa-auto-media-player/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker rename to aacs/android/app-components/alexa-auto-media-player/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker diff --git a/samples/android-aacs-sample-app/alexa-auto-app/.gitignore b/aacs/android/app-components/alexa-auto-navigation/.gitignore similarity index 100% rename from samples/android-aacs-sample-app/alexa-auto-app/.gitignore rename to aacs/android/app-components/alexa-auto-navigation/.gitignore diff --git a/platforms/android/app-components/alexa-auto-navigation/README.md b/aacs/android/app-components/alexa-auto-navigation/README.md similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/README.md rename to aacs/android/app-components/alexa-auto-navigation/README.md diff --git a/aacs/android/app-components/alexa-auto-navigation/build.gradle b/aacs/android/app-components/alexa-auto-navigation/build.gradle new file mode 100644 index 000000000..323334ccc --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/build.gradle @@ -0,0 +1,74 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-apps-navigation" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(path: ':aacscommonutils') + implementation project(path: ':aacsconstants') + implementation project(path: ':alexa-auto-apis') + implementation project(':alexa-auto-apps-common-ui') + implementation project(':alexa-auto-apps-common-util') + implementation project(':aacsipc') + + implementation deps.androidx_appcompat + implementation deps.androidx_recycler_view + implementation deps.androidx_constraint + + // Dagger + implementation deps.dagger + annotationProcessor deps.dagger_compiler + + // Glide + implementation deps.glide + annotationProcessor deps.glide_compiler + + //Eventbus + implementation deps.eventbus + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.androidx_test_core + testImplementation deps.androidx_arch_core_testing + testImplementation deps.roboelectric +} diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/proguard-rules.pro b/aacs/android/app-components/alexa-auto-navigation/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-navigation/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AACSModule.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AACSModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AACSModule.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AACSModule.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AndroidModule.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AndroidModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AndroidModule.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/AndroidModule.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/GoogleMapsModule.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/GoogleMapsModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/GoogleMapsModule.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/GoogleMapsModule.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/NavigationComponent.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/NavigationComponent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/NavigationComponent.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/dependencies/NavigationComponent.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandler.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandler.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandler.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandler.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandler.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandler.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/ClearTemplateEvent.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/ClearTemplateEvent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/ClearTemplateEvent.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/ClearTemplateEvent.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapter.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapter.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapter.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapter.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/NavigationProvider.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/NavigationProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/NavigationProvider.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/NavigationProvider.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProvider.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProvider.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProvider.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiver.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiver.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiver.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiver.java b/aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiver.java rename to aacs/android/app-components/alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiver.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/circle_background.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/circle_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/circle_background.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/circle_background.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/ic_cancel.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/ic_cancel.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/ic_cancel.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/ic_cancel.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/light_info_background.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/light_info_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/light_info_background.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/light_info_background.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/local_search_background.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/local_search_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/drawable/local_search_background.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/drawable/local_search_background.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml similarity index 98% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml index 6a2affe2e..fab4d122d 100644 --- a/platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_detail.xml @@ -30,8 +30,8 @@ diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_item.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_item.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_item.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_item.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml similarity index 96% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml index 2718e8888..496535b12 100644 --- a/platforms/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/layout/local_search_list.xml @@ -29,8 +29,8 @@ diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-de/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-de/strings.xml new file mode 100644 index 000000000..6a876c905 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-de/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navigieren + Anrufen +  -  + Alexa + Geschlossen + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rAU/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 000000000..6be3aa19d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navigate + Call +  -  + Alexa + Closed + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rCA/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rCA/strings.xml new file mode 100644 index 000000000..6be3aa19d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rCA/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navigate + Call +  -  + Alexa + Closed + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rIN/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 000000000..6be3aa19d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navigate + Call +  -  + Alexa + Closed + diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rUS/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en-rUS/strings.xml diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en/strings.xml new file mode 100644 index 000000000..6be3aa19d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-en/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navigate + Call +  -  + Alexa + Closed + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rMX/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 000000000..7be7b7b5d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navegación + Llamar +  -  + alexa + Cerrado + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rUS/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..7be7b7b5d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navegación + Llamar +  -  + alexa + Cerrado + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..450e7d038 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-es/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navegar + Llamar +  -  + alexa + Cerrado + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr-rCA/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000..68674c2db --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Naviguer + Appeler +  -  + Alexa + Fermé + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr/strings.xml new file mode 100644 index 000000000..fef410d09 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-fr/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Naviguer + Appeler +  -  + alexa + Fermé + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-hi-rIN/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-hi-rIN/strings.xml new file mode 100644 index 000000000..ceb60f591 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-hi-rIN/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + रास्ता ढूंढें + कॉल करें +  -  + alexa + बंद + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-it/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-it/strings.xml new file mode 100644 index 000000000..e78e5cf2c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-it/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Naviga + Chiama +  -  + alexa + Chiuso + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-ja/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-ja/strings.xml new file mode 100644 index 000000000..a8c91e902 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-ja/strings.xml @@ -0,0 +1,10 @@ + + + Alexaナビゲーション + Yelp + ナビゲーション + 通話 +  -  + alexa + 営業時間外 + diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/values-land/dimens.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-land/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/values-land/dimens.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/values-land/dimens.xml diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-pt-rBR/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000..034649a2c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navegar + Fazer chamada +  -  + Alexa + Fechado + diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/dimens.xml new file mode 100644 index 000000000..7cd64a7b1 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/dimens.xml @@ -0,0 +1,61 @@ + + + 32sp + 24sp + 20sp + 25dp + 20sp + 600dp + 580dp + 22dp + 13dp + 15dp + 50dp + 200dp + 65dp + 46dp + 110dp + 25dp + 15dp + 30dp + 1dp + 570dp + 30dp + 25dp + 550dp + 50dp + 20dp + 30dp + 10dp + 19dp + 15dp + 230dp + 5dp + 5dp + 5dp + 40dp + 200dp + 200dp + 25dp + 240dp + 340dp + 7dp + 23sp + 5dp + 15dp + 113dp + 20dp + 5dp + 95dp + 17dp + 5dp + 10dp + 3dp + 45dp + 20dp + 0dp + 800dp + 40dp + 20dp + #33EBEDED + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/values/ids.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/ids.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/values/ids.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/values/ids.xml diff --git a/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/strings.xml new file mode 100644 index 000000000..088aa4685 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/strings.xml @@ -0,0 +1,10 @@ + + + Alexa Navigation + Yelp + Navigate + Call +  -  + alexa + Closed + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-navigation/src/main/res/values/styles.xml b/aacs/android/app-components/alexa-auto-navigation/src/main/res/values/styles.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/main/res/values/styles.xml rename to aacs/android/app-components/alexa-auto-navigation/src/main/res/values/styles.xml diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandlerTest.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandlerTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandlerTest.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandlerTest.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandlerTest.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandlerTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandlerTest.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/handlers/NavigationDirectiveHandlerTest.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapterTest.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapterTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapterTest.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/poi/LocalSearchListAdapterTest.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProviderTest.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProviderTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProviderTest.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/providers/google/GoogleMapsNavigationProviderTest.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiverTest.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiverTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiverTest.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/LocalSearchTemplateRuntimeReceiverTest.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiverTest.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiverTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiverTest.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/NavigationReceiverTest.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/TestResourceFileReader.java b/aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/TestResourceFileReader.java similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/TestResourceFileReader.java rename to aacs/android/app-components/alexa-auto-navigation/src/test/java/com/amazon/alexa/auto/navigation/receiver/TestResourceFileReader.java diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/CancelNavigation.json b/aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/CancelNavigation.json similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/CancelNavigation.json rename to aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/CancelNavigation.json diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/ClearTemplate.json b/aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/ClearTemplate.json similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/ClearTemplate.json rename to aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/ClearTemplate.json diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/GetNavigationState.json b/aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/GetNavigationState.json similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/GetNavigationState.json rename to aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/GetNavigationState.json diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchDetail.json b/aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchDetail.json similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchDetail.json rename to aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchDetail.json diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchList.json b/aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchList.json similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchList.json rename to aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/RenderTemplateLocalSearchList.json diff --git a/platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/StartNavigation.json b/aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/StartNavigation.json similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/src/test/resources/aacs/StartNavigation.json rename to aacs/android/app-components/alexa-auto-navigation/src/test/resources/aacs/StartNavigation.json diff --git a/platforms/android/app-components/alexa-auto-settings/.gitignore b/aacs/android/app-components/alexa-auto-settings/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/.gitignore rename to aacs/android/app-components/alexa-auto-settings/.gitignore diff --git a/aacs/android/app-components/alexa-auto-settings/README.md b/aacs/android/app-components/alexa-auto-settings/README.md new file mode 100644 index 000000000..4dbf18d4b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/README.md @@ -0,0 +1,12 @@ +# Alexa Auto Settings + +This package provides code containing business logic and UI components for the settings menu which +is shown to the user after setup is successful. The `AlexaSettingsHomeFragment` houses top level +settings that are available to users. + +## Known Gaps +* The following features have not been developed on the settings screen yet + * Navigation favorites permission + * Push to talk + * Things to try +* Communication settings do not satisfy CX requirements. Refer to the HMI Guidelines - Communications section for guidance or work with your Amazon partner manager diff --git a/aacs/android/app-components/alexa-auto-settings/build.gradle b/aacs/android/app-components/alexa-auto-settings/build.gradle new file mode 100644 index 000000000..fd53b762b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/build.gradle @@ -0,0 +1,88 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + buildFeatures { + viewBinding = true + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-settings" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(':aacscommonutils') + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':alexa-auto-apps-common-util') + implementation project(':alexa-auto-apps-common-ui') + implementation project(':alexa-auto-apis') + implementation project(':alexa-auto-apps-common-ui') + implementation project(':alexa-auto-setup') + implementation project(':alexa-auto-comms-ui') + + implementation deps.kotlin_stdlib + implementation deps.androidx_appcompat + implementation deps.androidx_constraint + implementation deps.androidx_preference + + // RX + implementation deps.rxjava3 + + // Dagger + api deps.dagger + kapt deps.dagger_compiler + + // Navigation between UI components. + implementation deps.androidx_navigation_fragment + implementation deps.androidx_navigation_ui + + // Event Bus + implementation deps.eventbus + + //Test Dependencies + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.roboelectric + testImplementation deps.androidx_fragment_testing +} diff --git a/platforms/android/app-components/alexa-auto-device-usage/proguard-rules.pro b/aacs/android/app-components/alexa-auto-settings/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-device-usage/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-settings/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-settings/src/main/AndroidManifest.xml new file mode 100644 index 000000000..b16dd46b7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/AndroidManifest.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/assets/locales.json b/aacs/android/app-components/alexa-auto-settings/src/main/assets/locales.json new file mode 100644 index 000000000..5caaedb6c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/assets/locales.json @@ -0,0 +1,221 @@ +{ + "locales": [ + { + "id": "de-DE", + "locale": { + "language": "Deutsch", + "country": "Deutschland" + } + }, + { + "id": "de-DE/en-US", + "locale": { + "language": "Deutsch / English", + "country": "Deutschland / United States" + } + }, + { + "id": "en-AU", + "locale": { + "language": "English", + "country": "Australia / New Zealand" + } + }, + { + "id": "en-CA", + "locale": { + "language": "English", + "country": "Canada" + } + }, + { + "id": "en-CA/fr-CA", + "locale": { + "language": "English / Français", + "country": "Canada" + } + }, + { + "id": "en-IN", + "locale": { + "language": "English", + "country": "India" + } + }, + { + "id": "en-IN/hi-IN", + "locale": { + "language": "English / हिंदी", + "country": "India / भारत" + } + }, + { + "id": "en-GB", + "locale": { + "language": "English", + "country": "United Kingdom" + } + }, + { + "id": "en-US", + "locale": { + "language": "English", + "country": "United States" + } + }, + { + "id": "en-US/de-DE", + "locale": { + "language": "English / Deutsch", + "country": "United States / Deutschland" + } + }, + { + "id": "en-US/es-ES", + "locale": { + "language": "English / Español", + "country": "United States / España" + } + }, + { + "id": "en-US/es-US", + "locale": { + "language": "English / Español", + "country": "United States / Estados Unidos" + } + }, + { + "id": "en-US/fr-FR", + "locale": { + "language": "English / Français", + "country": "United States / France" + } + }, + { + "id": "en-US/it-IT", + "locale": { + "language": "English / Italiano", + "country": "United States / Italia" + } + }, + { + "id": "en-US/ja-JP", + "locale": { + "language": "English / 日本語", + "country": "United States / 日本" + } + }, + { + "id": "es-ES", + "locale": { + "language": "Español", + "country": "España" + } + }, + { + "id": "es-ES/en-US", + "locale": { + "language": "Español / English", + "country": "España / United States" + } + }, + { + "id": "es-US", + "locale": { + "language": "Español", + "country": "Estados Unidos" + } + }, + { + "id": "es-US/en-US", + "locale": { + "language": "Español / English", + "country": "Estados Unidos / United States" + } + }, + { + "id": "es-MX", + "locale": { + "language": "Español", + "country": "México" + } + }, + { + "id": "fr-CA", + "locale": { + "language": "Français", + "country": "Canada" + } + }, + { + "id": "fr-CA/en-CA", + "locale": { + "language": "Français / English", + "country": "Canada" + } + }, + { + "id": "fr-FR", + "locale": { + "language": "Français", + "country": "France" + } + }, + { + "id": "fr-FR/en-US", + "locale": { + "language": "Français / English", + "country": "France / United States" + } + }, + { + "id": "it-IT", + "locale": { + "language": "Italiano", + "country": "Italia" + } + }, + { + "id": "it-IT/en-US", + "locale": { + "language": "Italiano / English", + "country": "Italia / United States" + } + }, + { + "id": "pt-BR", + "locale": { + "language": "Português", + "country": "Brasil" + } + }, + { + "id": "hi-IN", + "locale": { + "language": "हिंदी", + "country": "भारत" + } + }, + { + "id": "hi-IN/en-IN", + "locale": { + "language": " हिंदी / English", + "country": "भारत / India" + } + }, + { + "id": "ja-JP", + "locale": { + "language": "日本語", + "country": "日本" + } + }, + { + "id": "ja-JP/en-US", + "locale": { + "language": "日本語 / English", + "country": "日本 / United States" + } + } + ] +} diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java similarity index 88% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java index 18acbe65d..2243e2da6 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSMetadataReceiver.java @@ -20,6 +20,7 @@ public class AACSMetadataReceiver extends BroadcastReceiver { private static final String TAG = AACSMetadataReceiver.class.getCanonicalName(); public static final String AACS_MODULE_GEOLOCATION = "geolocation"; + public static final String AACS_MODULE_LVC = "lvc"; /** * Scans through list of AACS extra modules in metadata object and adds modules @@ -57,6 +58,11 @@ public void onReceive(Context context, Intent intent) { ModuleProvider.addModule(context, ModuleProvider.ModuleName.GEOLOCATION.name()); Log.d(TAG, "Added AACS Geolocation module to list of extra modules"); } + if (AACS_MODULE_LVC.equals(extrasModuleListJSON.get(i).toString())) { + ModuleProvider.addModule(context, ModuleProvider.ModuleName.LVC.name()); + Log.d(TAG, "Added AACS LVC module to list of extra modules"); + } + } } catch (JSONException e) { Log.e(TAG, "Error while parsing aacs metadata reply intent" + e); diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSPreferenceFragment.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSPreferenceFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSPreferenceFragment.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AACSPreferenceFragment.java diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSettingsLanguagesFragment.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSettingsLanguagesFragment.java new file mode 100644 index 000000000..e92bdfe9b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSettingsLanguagesFragment.java @@ -0,0 +1,267 @@ +package com.amazon.alexa.auto.settings; + +import android.content.ComponentName; +import android.content.Intent; +import android.os.Bundle; +import android.util.Log; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.fragment.app.Fragment; + +import com.amazon.aacsconstants.AACSConstants; +import com.amazon.aacsconstants.AACSPropertyConstants; +import com.amazon.alexa.auto.apps.common.aacs.AACSServiceController; +import com.amazon.alexa.auto.apps.common.util.ModuleProvider; +import com.amazon.alexa.auto.apps.common.util.config.AlexaPropertyManager; +import com.amazon.alexa.auto.apps.common.util.config.LocalesProvider; +import com.amazon.alexa.auto.settings.config.PreferenceKeys; +import com.amazon.alexa.auto.settings.dependencies.AndroidModule; +import com.amazon.alexa.auto.settings.dependencies.DaggerSettingsComponent; +import com.amazon.alexa.auto.setup.workflow.WorkflowMessage; +import com.amazon.alexa.auto.setup.workflow.event.LoginEvent; + +import org.greenrobot.eventbus.EventBus; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Objects; +import java.util.Optional; + +import javax.inject.Inject; + +import io.reactivex.rxjava3.disposables.CompositeDisposable; + +public class AlexaSettingsLanguagesFragment extends Fragment { + private static final String TAG = AlexaSettingsLanguagesFragment.class.getSimpleName(); + + @Inject + AlexaPropertyManager mAlexaPropertyManager; + + @Inject + LocalesProvider mLocalesProvider; + + private HashMap languageList; + private HashMap languageCheckerList; + private CompositeDisposable mInFlightOperations; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + DaggerSettingsComponent.builder().androidModule(new AndroidModule(getContext())).build().inject(this); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + View view = inflater.inflate(R.layout.settings_alexa_language_layout, container, false); + + mInFlightOperations = new CompositeDisposable(); + setUpLocalesList(view); + monitorLocalesChange(); + + if (getArguments() != null) { + if (getArguments().getBoolean("showContinueButton")) { + TextView continueButton = view.findViewById(R.id.continueButton); + continueButton.setVisibility(View.VISIBLE); + continueButton.setOnClickListener(languagesView -> languageSelectionComplete()); + } + } + + return view; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mInFlightOperations.dispose(); + } + + /** + * Setup locales in Alexa languages settings based on supported locales list. + */ + private void setUpLocalesList(View view) { + languageList = new HashMap<>(); + languageCheckerList = new HashMap<>(); + + if (ModuleProvider.isAlexaCustomAssistantEnabled(view.getContext())) { + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_DE_DE, view.findViewById(R.id.deDE)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_CA, view.findViewById(R.id.enCA)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_GB, view.findViewById(R.id.enGB)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US, view.findViewById(R.id.enUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_MX, view.findViewById(R.id.esMX)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_CA, view.findViewById(R.id.frCA)); + + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_DE_DE, view.findViewById(R.id.deDEImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_CA, view.findViewById(R.id.enCAImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_GB, view.findViewById(R.id.enGBImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US, view.findViewById(R.id.enUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_MX, view.findViewById(R.id.esMXImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_CA, view.findViewById(R.id.frCAImage)); + + view.findViewById(R.id.esUSLayout).setVisibility(View.GONE); + view.findViewById(R.id.enAULayout).setVisibility(View.GONE); + view.findViewById(R.id.enINLayout).setVisibility(View.GONE); + view.findViewById(R.id.esESLayout).setVisibility(View.GONE); + view.findViewById(R.id.frFRLayout).setVisibility(View.GONE); + view.findViewById(R.id.hiINLayout).setVisibility(View.GONE); + view.findViewById(R.id.itITLayout).setVisibility(View.GONE); + view.findViewById(R.id.jaJPLayout).setVisibility(View.GONE); + view.findViewById(R.id.ptBRLayout).setVisibility(View.GONE); + view.findViewById(R.id.enCAfrCALayout).setVisibility(View.GONE); + view.findViewById(R.id.enINhiINLayout).setVisibility(View.GONE); + view.findViewById(R.id.enUSesUsLayout).setVisibility(View.GONE); + view.findViewById(R.id.esUsenUSLayout).setVisibility(View.GONE); + view.findViewById(R.id.frCAenCALayout).setVisibility(View.GONE); + view.findViewById(R.id.hiINenINLayout).setVisibility(View.GONE); + view.findViewById(R.id.enUSfrFRLayout).setVisibility(View.GONE); + view.findViewById(R.id.frFRenUSLayout).setVisibility(View.GONE); + view.findViewById(R.id.enUSdeDELayout).setVisibility(View.GONE); + view.findViewById(R.id.deDEenUSLayout).setVisibility(View.GONE); + view.findViewById(R.id.enUSjaJPLayout).setVisibility(View.GONE); + view.findViewById(R.id.enUSitITLayout).setVisibility(View.GONE); + view.findViewById(R.id.jaJPenUSLayout).setVisibility(View.GONE); + view.findViewById(R.id.itITenUSLayout).setVisibility(View.GONE); + view.findViewById(R.id.enUSesESLayout).setVisibility(View.GONE); + view.findViewById(R.id.esESenUSLayout).setVisibility(View.GONE); + } else { + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_DE_DE, view.findViewById(R.id.deDE)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_DE_DE_EN_US, view.findViewById(R.id.deDEenUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_AU, view.findViewById(R.id.enAU)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_CA, view.findViewById(R.id.enCA)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_CA_FR_CA, view.findViewById(R.id.enCAfrCA)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_IN, view.findViewById(R.id.enIN)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_IN_HI_IN, view.findViewById(R.id.enINhiIN)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_GB, view.findViewById(R.id.enGB)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US, view.findViewById(R.id.enUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_DE_DE, view.findViewById(R.id.enUSdeDE)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_ES_ES, view.findViewById(R.id.enUSesES)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_ES_US, view.findViewById(R.id.enUSesUs)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_FR_FR, view.findViewById(R.id.enUSfrFR)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_IT_IT, view.findViewById(R.id.enUSitIT)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_JA_JP, view.findViewById(R.id.enUSjaJP)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_ES, view.findViewById(R.id.esES)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_ES_EN_US, view.findViewById(R.id.esESenUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_US, view.findViewById(R.id.esUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_US_EN_US, view.findViewById(R.id.esUsenUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_MX, view.findViewById(R.id.esMX)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_CA, view.findViewById(R.id.frCA)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_CA_EN_CA, view.findViewById(R.id.frCAenCA)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_FR, view.findViewById(R.id.frFR)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_FR_EN_US, view.findViewById(R.id.frFRenUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_IT_IT, view.findViewById(R.id.itIT)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_IT_IT_EN_US, view.findViewById(R.id.itITenUS)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_PT_BR, view.findViewById(R.id.ptBR)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_HI_IN, view.findViewById(R.id.hiIN)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_HI_IN_EN_IN, view.findViewById(R.id.hiINenIN)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_JA_JP, view.findViewById(R.id.jaJP)); + languageList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_JA_JP_EN_US, view.findViewById(R.id.jaJPenUS)); + + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_DE_DE, view.findViewById(R.id.deDEImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_DE_DE_EN_US, view.findViewById(R.id.deDEenUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_AU, view.findViewById(R.id.enAUImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_CA, view.findViewById(R.id.enCAImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_CA_FR_CA, view.findViewById(R.id.enCAfrCAImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_IN, view.findViewById(R.id.enINImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_IN_HI_IN, view.findViewById(R.id.enINhiINImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_GB, view.findViewById(R.id.enGBImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US, view.findViewById(R.id.enUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_DE_DE, view.findViewById(R.id.enUSdeDEImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_ES_ES, view.findViewById(R.id.enUSesESImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_ES_US, view.findViewById(R.id.enUSesUsImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_FR_FR, view.findViewById(R.id.enUSfrFRImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_IT_IT, view.findViewById(R.id.enUSitITImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_EN_US_JA_JP, view.findViewById(R.id.enUSjaJPImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_ES, view.findViewById(R.id.esESImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_ES_EN_US, view.findViewById(R.id.esESenUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_US, view.findViewById(R.id.esUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_US_EN_US, view.findViewById(R.id.esUsenUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_ES_MX, view.findViewById(R.id.esMXImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_CA, view.findViewById(R.id.frCAImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_CA_EN_CA, view.findViewById(R.id.frCAenCAImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_FR, view.findViewById(R.id.frFRImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_FR_FR_EN_US, view.findViewById(R.id.frFRenUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_IT_IT, view.findViewById(R.id.itITImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_IT_IT_EN_US, view.findViewById(R.id.itITenUSImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_PT_BR, view.findViewById(R.id.ptBRImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_HI_IN, view.findViewById(R.id.hiINImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_HI_IN_EN_IN, view.findViewById(R.id.hiINenINImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_JA_JP, view.findViewById(R.id.jaJPImage)); + languageCheckerList.put(PreferenceKeys.ALEXA_SETTINGS_LANGUAGES_JA_JP_EN_US, view.findViewById(R.id.jaJPenUSImage)); + } + + mInFlightOperations.add( + mAlexaPropertyManager.getAlexaProperty(AACSPropertyConstants.LOCALE) + .filter(Optional::isPresent) + .map(Optional::get) + .subscribe(alexaLocale -> { + mInFlightOperations.add( + mLocalesProvider.fetchAlexaSupportedLocales().subscribe(supportedLocalesMap -> { + languageList.forEach((localeId, viewGroup) -> { + Pair languageCountry = supportedLocalesMap.get(localeId); + if (languageCountry != null) { + TextView languageTitle = (TextView) viewGroup.getChildAt(0); + TextView languageSummary = (TextView) viewGroup.getChildAt(1); + + languageTitle.setText(languageCountry.first); + languageSummary.setText(languageCountry.second); + + if (localeId.equals(alexaLocale)) { + selectLocaleChoice( + Objects.requireNonNull(languageCheckerList.get(localeId))); + } + } + }); + })); + })); + } + + /** + * Monitor locale update and reset locale choice. + */ + private void monitorLocalesChange() { + languageList.forEach((language, viewGroup) -> { + viewGroup.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + selectLocaleChoice(Objects.requireNonNull(languageCheckerList.get(language))); + mAlexaPropertyManager.updateAlexaProperty(AACSPropertyConstants.LOCALE, language) + .subscribe((succeeded) -> { + if (!succeeded) { + Log.w(TAG, "Failed to update locale to: " + language); + } + }); + disableLocaleSyncWithSystem(); + } + }); + }); + } + + private void selectLocaleChoice(ImageView currentCheckBox) { + languageCheckerList.forEach((language, imageView) -> { imageView.setVisibility(View.GONE); }); + currentCheckBox.setVisibility(View.VISIBLE); + } + + /** + * Sending workflow event of language selection complete. + */ + private void languageSelectionComplete() { + Log.d(TAG, "Language selection is completed."); + EventBus.getDefault().post(new WorkflowMessage(LoginEvent.LANGUAGE_SELECTION_COMPLETE_EVENT)); + } + + private void disableLocaleSyncWithSystem() { + Log.d(TAG, "A locale has been manually selected. Disabling locale syncing with system setting."); + Intent intent = new Intent(AACSConstants.IntentAction.DISABLE_SYNC_SYSTEM_PROPERTY_CHANGE); + intent.addCategory(AACSConstants.IntentCategory.SYNC_SYSTEM_PROPERTY_CHANGE_ENABLEMENT); + intent.putExtra(AACSPropertyConstants.PROPERTY, AACSPropertyConstants.LOCALE); + intent.setComponent(new ComponentName(AACSConstants.getAACSPackageName(new WeakReference<>(getContext())), + AACSConstants.AACS_CLASS_NAME)); + AACSServiceController.checkAndroidVersionAndStartService(getContext(), intent); + } +} diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragment.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragment.java new file mode 100644 index 000000000..85a6b275d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragment.java @@ -0,0 +1,101 @@ +package com.amazon.alexa.auto.settings; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreferenceCompat; + +import com.amazon.alexa.auto.apps.common.util.ModuleProvider; +import com.amazon.alexa.auto.settings.config.PreferenceKeys; + +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.isEndEarconSettingEnabled; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.isStartEarconSettingEnabled; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.setEndEarconSetting; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.setStartEarconSetting; + + +public class AlexaSoundPreferencesFragment extends PreferenceFragmentCompat { + private static final String TAG = AlexaSoundPreferencesFragment.class.getSimpleName(); + + Context mContext; + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + setPreferencesFromResource(R.xml.alexa_sound_preferences, rootKey); + + if (mContext == null) { + mContext = getContext(); + } + setDefaultPreferences(); + } + + @VisibleForTesting + void setDefaultPreferences() { + PreferenceManager.setDefaultValues(mContext, R.xml.alexa_sound_preferences, false); + } + + @Override + public void onRequestPermissionsResult( + int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + PreferenceScreen screen = getPreferenceScreen(); + if (ModuleProvider.isAlexaCustomAssistantEnabled(view.getContext())) { + Preference earconStartSoundPref = screen.findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_START); + earconStartSoundPref.setSummary(R.string.setting_voice_assistance_sounds_request_start_summary); + Preference earconEndSoundPref = screen.findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_END); + earconEndSoundPref.setSummary(R.string.setting_voice_assistance_sounds_request_end_summary); + } + + SwitchPreferenceCompat defaultSoundStartSetting = + findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_START); + defaultSoundStartSetting.setChecked(isStartEarconSettingEnabled(mContext)); + + defaultSoundStartSetting.setOnPreferenceChangeListener((preference, newValue) -> { + Log.d(TAG, "Changing earcon sound start setting to:" + newValue); + setStartEarconSetting(mContext, (boolean) newValue); + return true; + }); + + SwitchPreferenceCompat defaultSoundEndSetting = + findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_END); + + defaultSoundEndSetting.setChecked(isEndEarconSettingEnabled(mContext)); + + defaultSoundEndSetting.setOnPreferenceChangeListener((preference, newValue) -> { + Log.d(TAG, "Changing earcon sound end setting to:" + newValue); + setEndEarconSetting(mContext, (boolean) newValue); + return true; + }); + + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + if (layoutParams instanceof ViewGroup.MarginLayoutParams) { + ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams; + marginLayoutParams.setMarginStart( + (int) getResources().getDimension(R.dimen.item_horizontal_margin_quadruple)); + marginLayoutParams.setMarginEnd((int) getResources().getDimension(R.dimen.item_horizontal_margin_double)); + view.setLayoutParams(layoutParams); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + } + +} diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDChangeMessage.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDChangeMessage.java new file mode 100644 index 000000000..5b5bef2b2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDChangeMessage.java @@ -0,0 +1,17 @@ +package com.amazon.alexa.auto.settings; + +/** + * Holds do not disturb change attributes + */ +public class DNDChangeMessage { + + private boolean checked; + + public DNDChangeMessage(boolean checked) { + this.checked = checked; + } + + public boolean isChecked() { + return checked; + } +} diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDReceiver.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDReceiver.java new file mode 100644 index 000000000..14da2305f --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/DNDReceiver.java @@ -0,0 +1,59 @@ +package com.amazon.alexa.auto.settings; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; + +import org.greenrobot.eventbus.EventBus; +import org.json.JSONException; +import org.json.JSONObject; + +import static com.amazon.aacsconstants.Action.DoNotDisturb.SET_DO_NOT_DISTURB; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.DO_NOT_DISTURB_JSON_KEY; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.isDNDSettingEnabled; + +/** + * Receives Do Not Disturb intents that are broadcast by AACS + */ +public class DNDReceiver extends BroadcastReceiver { + private static final String TAG = DNDReceiver.class.getCanonicalName(); + + /** + * Listens for Do not disturb messages and updates Shared Preferences accordingly + * + * @param context + * @param intent + */ + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceived"); + if (intent == null || intent.getAction() == null) { + return; + } + Log.d(TAG, intent.getAction()); + + AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { + if (SET_DO_NOT_DISTURB.equals(message.action)) { + if (message.payload == null || message.payload.isEmpty()) { + Log.w(TAG, "Received invalid payload"); + return; + } + + try { + JSONObject messagePayload = new JSONObject(message.payload); + boolean value = messagePayload.getBoolean(DO_NOT_DISTURB_JSON_KEY); + if (isDNDSettingEnabled(context) != value) { + EventBus.getDefault().post(new DNDChangeMessage(value)); + } + } catch (JSONException e) { + Log.e(TAG, "Error while parsing do not disturb intent" + e); + } + } else { + Log.d(TAG, "Intent action not handled. Action:" + message.action); + } + }); + } +} diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java similarity index 96% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java index b57b52f26..763266ebe 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivity.java @@ -30,6 +30,7 @@ import java.util.Optional; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; import static com.amazon.aacsconstants.NetworkConstants.ANDROID_CONNECTIVITY_CHANGE_ACTION; import static com.amazon.alexa.auto.apps.common.Constants.CBL_START; import static com.amazon.alexa.auto.apps.common.Constants.SETUP_DONE; @@ -136,10 +137,14 @@ private void startObservingAuthEvents() { break; case LOGGED_OUT: if (!isSetupCompleted && !currentNavDestinationIsLogin) { + mViewModel.disableWakeWord(); resetNavigationGraphWithLoginAsInitialDestination(); } break; case CBL_START: + // When user starts cbl login, preview mode auth gets deactivated in AACS + // This is a temp logic to enable wakeword until fixed in AACS layer + mViewModel.disableWakeWord(); resetNavigationGraphWithCBLAsInitialDestination(); break; } @@ -203,6 +208,8 @@ private void setupNavigationBarListener() { mViewModel.transitionToLoggedOutState(); } else if (id == R.id.navigation_fragment_authProviderAuthenticatedFinish || id == R.id.navigation_fragment_cblLoginFinish) { + // When the user clicks on back on these screens, it should behave the same as clicking on done. + mViewModel.loginFinished(); resetNavigationGraphToOriginalState(); } }); diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java similarity index 83% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java index 40a0eb71e..c2f4b1c5d 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/SettingsActivityViewModel.java @@ -1,6 +1,7 @@ package com.amazon.alexa.auto.settings; import android.app.Application; +import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; @@ -17,7 +18,6 @@ import com.amazon.alexa.auto.apis.auth.AuthStatus; import com.amazon.alexa.auto.apis.login.LoginUIEventListener; import com.amazon.alexa.auto.apis.setup.AlexaSetupController; -import com.amazon.alexa.auto.apps.common.util.ModuleProvider; import com.amazon.alexa.auto.apps.common.util.config.AlexaPropertyManager; import com.amazon.alexa.auto.apps.common.util.config.LocalesProvider; import com.amazon.alexa.auto.settings.dependencies.AndroidModule; @@ -27,7 +27,9 @@ import io.reactivex.rxjava3.disposables.Disposable; -import static com.amazon.alexa.auto.setup.workflow.model.LocationConsent.DISABLED; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.resetDNDSetting; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.resetEarconSettings; /** * ViewModel for {@link SettingsActivity}. @@ -114,6 +116,7 @@ public void transitionToLoggedOutState() { Log.i(TAG, "Transitioning to logged out state."); disposeLoggedInStateSubscriptions(); + resetUserPreferences(getApplication().getApplicationContext()); mAuthState.setValue(AuthState.LOGGED_OUT); @@ -135,6 +138,15 @@ public void uninitialize() { deactivateLoggedOutScope(); } + /** + * Reset preferences to default values + * @param context + */ + private void resetUserPreferences(Context context) { + resetEarconSettings(context); + resetDNDSetting(context); + } + /** * Deactivate the logged out state apparatus. */ @@ -187,4 +199,24 @@ public void loginSwitched(AuthMode mode) { public LiveData getAuthState() { return mAuthState; } + + public void disableWakeWord() { + mAlexaPropertyManager.updateAlexaProperty(WAKEWORD_ENABLED, "false") + .doOnSuccess((succeeded) -> { + if (!succeeded) { + Log.d(TAG, " Wakeword disable failed "); + } + }) + .subscribe(); + } + + public void enableWakeWord() { + mAlexaPropertyManager.updateAlexaProperty(WAKEWORD_ENABLED, "true") + .doOnSuccess((succeeded) -> { + if (!succeeded) { + Log.d(TAG, " Wakeword enable failed "); + } + }) + .subscribe(); + } } diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfiguration.kt b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfiguration.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfiguration.kt rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfiguration.kt diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurationPreferences.kt b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurationPreferences.kt similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurationPreferences.kt rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurationPreferences.kt diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java similarity index 98% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java index 6d51c0ea6..2b3178c47 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/AACSConfigurator.java @@ -90,7 +90,7 @@ public void configureAACSUsingDefaultAppConfig() { * Configure AACS with preference overrides. */ public void configureAACSWithPreferenceOverrides() { - Log.i(TAG, "Configuring Alexa Client Service with default app config."); + Log.i(TAG, "Configuring Alexa Client Service with preference overrides."); Context context = mContextWk.get(); Preconditions.checkNotNull(context); @@ -107,6 +107,7 @@ public void configureAACSWithPreferenceOverrides() { * would need to share those wake word models with AACS for it to successfully load during runtime. */ public void shareFilesWithAACS(@NonNull Context context) { + Log.i(TAG, "sharing files with AACS"); File fileDir = context.getFilesDir(); // Sharing wake word models diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/PreferenceKeys.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/PreferenceKeys.java new file mode 100644 index 000000000..a7e791dfb --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/config/PreferenceKeys.java @@ -0,0 +1,72 @@ +package com.amazon.alexa.auto.settings.config; + +public class PreferenceKeys { + public static final String AACS_OVERRIDE_CONFIG = "aacs-override-base-config"; + + public static final String AACS_CONFIG_AVS_DEVICE_CLIENT_ID = "avs-device-clientid"; + public static final String AACS_CONFIG_AVS_DEVICE_PRODUCT_ID = "avs-device-productid"; + public static final String AACS_CONFIG_AVS_DEVICE_DSN = "avs-device-dsn"; + public static final String AACS_CONFIG_AVS_DEVICE_MANUFACTURER = "avs-device-manufacturer"; + + public static final String AACS_CONFIG_AACS_START_ON_BOOT = "aacs-startonboot"; + + public static final String AACS_CONFIG_USE_AACS_AUDIO_INPUT = "aacs-audio-input-internal"; + + public static final String AACS_CONFIG_CONTROL_RESTART_APPLY_CONFIG = "aacs-reboot-apply-config"; + public static final String AACS_CONFIG_CONTROL_SHUTDOWN = "aacs-shutdown"; + public static final String AACS_CONFIG_CONTROL_START = "aacs-start"; + + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_NONALEXA = "voice-assistance-nonalexa"; + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_ALEXA = "voice-assistance-alexa"; + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_DISABLE_NONALEXA = "voice-assistance-disable-nonalexa"; + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_ENABLE_NONALEXA = "voice-assistance-enable-nonalexa"; + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_ENABLE_ALEXA = "voice-assistance-enable-alexa"; + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_PUSH_TO_TALK = "voice-assistance-push-to-talk"; + public static final String ALEXA_SETTINGS_VOICE_ASSISTANCE_PUSH_TO_TALK_SELECTION = "voice-assistance-push-to-talk-selection"; + public static final String ALEXA_SETTINGS_HANDS_FREE = "alexa-hands-free-settings"; + public static final String ALEXA_SETTINGS_LOCATION_CONSENT = "alexa-location-consent-setting"; + public static final String ALEXA_SETTINGS_LANGUAGES = "alexa-languages-settings"; + public static final String ALEXA_SETTINGS_SIGNIN = "alexa-signin"; + public static final String ALEXA_SETTINGS_SIGNOUT = "alexa-signout"; + public static final String ALEXA_SETTINGS_DISABLE = "alexa-disable"; + public static final String ALEXA_SETTINGS_DISABLE_NON_ALEXA = "non-alexa-disable"; + public static final String ALEXA_SETTINGS_AACS = "alexa-auto-client-service-settings"; + public static final String ALEXA_SETTINGS_DO_NOT_DISTURB = "alexa-dnd-setting"; + public static final String ALEXA_SETTINGS_COMMUNICATION = "alexa-communication"; + public static final String ALEXA_SETTINGS_SOUNDS = "alexa-sounds"; + + public static final String ALEXA_SETTINGS_SOUND_START = "alexa-sound-start"; + public static final String ALEXA_SETTINGS_SOUND_END = "alexa-sound-end"; + + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US = "en-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_ES_US = "es-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_DE_DE = "de-DE"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_AU = "en-AU"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_CA = "en-CA"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_GB = "en-GB"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_IN = "en-IN"; + public static final String ALEXA_SETTINGS_LANGUAGES_ES_ES = "es-ES"; + public static final String ALEXA_SETTINGS_LANGUAGES_ES_MX = "es-MX"; + public static final String ALEXA_SETTINGS_LANGUAGES_FR_CA = "fr-CA"; + public static final String ALEXA_SETTINGS_LANGUAGES_FR_FR = "fr-FR"; + public static final String ALEXA_SETTINGS_LANGUAGES_HI_IN = "hi-IN"; + public static final String ALEXA_SETTINGS_LANGUAGES_IT_IT = "it-IT"; + public static final String ALEXA_SETTINGS_LANGUAGES_JA_JP = "ja-JP"; + public static final String ALEXA_SETTINGS_LANGUAGES_PT_BR = "pt-BR"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US_ES_US = "en-US/es-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_ES_US_EN_US = "es-US/en-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_CA_FR_CA = "en-CA/fr-CA"; + public static final String ALEXA_SETTINGS_LANGUAGES_FR_CA_EN_CA = "fr-CA/en-CA"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_IN_HI_IN = "en-IN/hi-IN"; + public static final String ALEXA_SETTINGS_LANGUAGES_HI_IN_EN_IN = "hi-IN/en-IN"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US_FR_FR = "en-US/fr-FR"; + public static final String ALEXA_SETTINGS_LANGUAGES_FR_FR_EN_US = "fr-FR/en-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US_DE_DE = "en-US/de-DE"; + public static final String ALEXA_SETTINGS_LANGUAGES_DE_DE_EN_US = "de-DE/en-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US_JA_JP = "en-US/ja-JP"; + public static final String ALEXA_SETTINGS_LANGUAGES_JA_JP_EN_US = "ja-JP/en-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US_IT_IT = "en-US/it-IT"; + public static final String ALEXA_SETTINGS_LANGUAGES_IT_IT_EN_US = "it-IT/en-US"; + public static final String ALEXA_SETTINGS_LANGUAGES_EN_US_ES_ES = "en-US/es-ES"; + public static final String ALEXA_SETTINGS_LANGUAGES_ES_ES_EN_US = "es-ES/en-US"; +} diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AACSModule.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AACSModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AACSModule.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AACSModule.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AndroidModule.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AndroidModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AndroidModule.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/AndroidModule.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/ConfigModule.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/ConfigModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/ConfigModule.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/ConfigModule.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/MenuModule.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/MenuModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/MenuModule.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/MenuModule.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java similarity index 83% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java index 9984f6cce..3fa998fa2 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/dependencies/SettingsComponent.java @@ -2,6 +2,7 @@ import com.amazon.alexa.auto.settings.AACSPreferenceFragment; import com.amazon.alexa.auto.settings.AlexaSettingsLanguagesFragment; +import com.amazon.alexa.auto.settings.AlexaSoundPreferencesFragment; import com.amazon.alexa.auto.settings.SettingsActivityViewModel; import com.amazon.alexa.auto.settings.home.AlexaSettingsHomeFragment; @@ -42,4 +43,11 @@ public interface SettingsComponent { * @param fragment Object whose dependencies are resolved by dagger. */ void inject(AACSPreferenceFragment fragment); + + /** + * Inject to @{link AlexaSoundPreferencesFragment}. + * + * @param fragment Object whose dependencies are resolved by dagger. + */ + void inject(AlexaSoundPreferencesFragment fragment); } diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java similarity index 90% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java index ecd49051f..f6b943bff 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragment.java @@ -1,12 +1,5 @@ package com.amazon.alexa.auto.settings.home; -import static com.amazon.aacsconstants.AACSPropertyConstants.GEOLOCATION_ENABLED; -import static com.amazon.aacsconstants.AACSPropertyConstants.LOCALE; -import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; -import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_SUPPORTED; -import static com.amazon.alexa.auto.setup.workflow.model.LocationConsent.DISABLED; -import static com.amazon.alexa.auto.setup.workflow.model.LocationConsent.ENABLED; - import android.content.Context; import android.os.Bundle; import android.util.Log; @@ -36,12 +29,16 @@ import com.amazon.alexa.auto.comms.ui.db.BTDeviceRepository; import com.amazon.alexa.auto.comms.ui.db.ConnectedBTDevice; import com.amazon.alexa.auto.comms.ui.db.ConnectedBTDeviceRepository; +import com.amazon.alexa.auto.settings.DNDChangeMessage; import com.amazon.alexa.auto.settings.R; import com.amazon.alexa.auto.settings.config.PreferenceKeys; import com.amazon.alexa.auto.settings.dependencies.AndroidModule; import com.amazon.alexa.auto.settings.dependencies.DaggerSettingsComponent; import com.amazon.alexa.auto.setup.workflow.model.LocationConsent; +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + import java.util.List; import java.util.Optional; @@ -49,6 +46,14 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable; +import static com.amazon.aacsconstants.AACSPropertyConstants.GEOLOCATION_ENABLED; +import static com.amazon.aacsconstants.AACSPropertyConstants.LOCALE; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_SUPPORTED; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.updateDNDInPreferences; +import static com.amazon.alexa.auto.setup.workflow.model.LocationConsent.DISABLED; +import static com.amazon.alexa.auto.setup.workflow.model.LocationConsent.ENABLED; + /** * Settings fragment for Alexa menu home screen. */ @@ -98,6 +103,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat installHandsFreeEventHandler(); installLocationConsentHandler(); installLanguageEventHandler(); + installSoundsEventHandler(); if (!isPreviewMode() || ModuleProvider.isAlexaCustomAssistantEnabled(view.getContext())) { installCommunicationsEventHandler(); @@ -119,6 +125,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat marginLayoutParams.setMarginEnd((int) getResources().getDimension(R.dimen.item_horizontal_margin_double)); view.setLayoutParams(layoutParams); } + EventBus.getDefault().register(this); } @Override @@ -126,6 +133,7 @@ public void onDestroyView() { super.onDestroyView(); mInFlightOperations.dispose(); mScreenBuilders.forEach(AlexaSettingsScreenBuilder::dispose); + EventBus.getDefault().unregister(this); } private void installHandsFreeEventHandler() { @@ -228,6 +236,20 @@ private void installLanguageEventHandler() { }); } + private void installSoundsEventHandler() { + Preference defaultAlexaSounds = findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUNDS); + Preconditions.checkNotNull(defaultAlexaSounds); + + defaultAlexaSounds.setOnPreferenceClickListener(preference -> { + View view = getView(); + if (view != null) { + NavController navController = findNavController(view); + navController.navigate(R.id.navigation_fragment_alexa_settings_sounds); + } + return false; + }); + } + private void installCommunicationsEventHandler() { Preference defaultAlexaComms = findPreference(PreferenceKeys.ALEXA_SETTINGS_COMMUNICATION); Preconditions.checkNotNull(defaultAlexaComms); @@ -263,6 +285,18 @@ private void installCommunicationsEventHandler() { }); } + @Subscribe + public void onDNDChangedEvent(@NonNull DNDChangeMessage message) { + SwitchPreferenceCompat defaultAlexaDNDSetting = + findPreference(PreferenceKeys.ALEXA_SETTINGS_DO_NOT_DISTURB); + if (defaultAlexaDNDSetting != null) { + if (defaultAlexaDNDSetting.isChecked() != message.isChecked()) { + defaultAlexaDNDSetting.setChecked(message.isChecked()); + updateDNDInPreferences(getContext(), message.isChecked()); + } + } + } + @VisibleForTesting NavController findNavController(@NonNull View view) { return Navigation.findNavController(view); diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsScreenBuilder.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsScreenBuilder.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsScreenBuilder.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AlexaSettingsScreenBuilder.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java similarity index 85% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java index 2a6c177e8..6530f9819 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java +++ b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilder.java @@ -10,6 +10,7 @@ import androidx.fragment.app.FragmentManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreferenceCompat; import com.amazon.alexa.auto.apis.app.AlexaApp; import com.amazon.alexa.auto.apis.auth.AuthController; @@ -17,14 +18,16 @@ import com.amazon.alexa.auto.apis.login.LoginUIEventListener; import com.amazon.alexa.auto.apis.setup.AlexaSetupController; import com.amazon.alexa.auto.app.common.ui.TwoChoiceDialog; -import com.amazon.alexa.auto.apps.common.aacs.AACSServiceController; -import com.amazon.alexa.auto.apps.common.util.ModuleProvider; import com.amazon.alexa.auto.settings.R; import com.amazon.alexa.auto.settings.config.PreferenceKeys; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.isDNDSettingEnabled; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.updateDNDSetting; +import static com.amazon.alexa.auto.apps.common.util.ModuleProvider.isAlexaCustomAssistantEnabled; + /** * Alexa menu builder to take care of Auth related settings. */ @@ -56,12 +59,14 @@ public void addRemovePreferences(@NonNull PreferenceScreen screen) { if (signOutPref != null) screen.removePreference(signOutPref); - if (!ModuleProvider.isAlexaCustomAssistantEnabled(screen.getContext())) { + if (!isAlexaCustomAssistantEnabled(screen.getContext())) { Preference commsPref = screen.findPreference(PreferenceKeys.ALEXA_SETTINGS_COMMUNICATION); if (commsPref != null) screen.removePreference(commsPref); } + } + if (isPreviewMode() || isAlexaCustomAssistantEnabled(screen.getContext())) { Preference dndPref = screen.findPreference(PreferenceKeys.ALEXA_SETTINGS_DO_NOT_DISTURB); if (dndPref != null) screen.removePreference(dndPref); @@ -84,8 +89,9 @@ public void installEventHandlers(@NonNull PreferenceScreen screen, @NonNull View mAlexaSetupController = fetchAlexaSetupController(view.getContext()); } - if (!isPreviewMode()) { + if (!isPreviewMode() && mAuthController.isAuthenticated()) { installSignoutEventHandler(screen, view); + installDNDEventHandler(screen, view); } else { installDisableAlexaEventHandler(screen, view); installSigninEventHandler(screen, view); @@ -99,6 +105,19 @@ public void dispose() { EventBus.getDefault().unregister(this); } + private void installDNDEventHandler(@NonNull PreferenceScreen screen, @NonNull View view) { + SwitchPreferenceCompat defaultAlexaDNDSetting = + screen.findPreference(PreferenceKeys.ALEXA_SETTINGS_DO_NOT_DISTURB); + if (defaultAlexaDNDSetting != null) { + defaultAlexaDNDSetting.setChecked(isDNDSettingEnabled(view.getContext())); + + defaultAlexaDNDSetting.setOnPreferenceChangeListener((preference, newValue) -> { + Log.d(TAG, "Changing DND setting to:" + newValue); + return updateDNDSetting(view.getContext(), (boolean) newValue); + }); + } + } + private void installSignoutEventHandler(@NonNull PreferenceScreen screen, @NonNull View view) { Preference signOutPref = screen.findPreference(PreferenceKeys.ALEXA_SETTINGS_SIGNOUT); if (signOutPref != null) { diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilder.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilder.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilder.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilder.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilder.java b/aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilder.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilder.java rename to aacs/android/app-components/alexa-auto-settings/src/main/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilder.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_arrow_back.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_arrow_back.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_arrow_back.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_arrow_back.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_check.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_check.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_check.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/drawable/ic_check.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_last_preference_layout.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_last_preference_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_last_preference_layout.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_last_preference_layout.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_preference_layout.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_preference_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_preference_layout.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/layout/alexa_preference_layout.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/layout/navigation_bar_layout.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/navigation_bar_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/layout/navigation_bar_layout.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/layout/navigation_bar_layout.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/layout/settings_activity_layout.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/settings_activity_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/layout/settings_activity_layout.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/layout/settings_activity_layout.xml diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/settings_alexa_language_layout.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/settings_alexa_language_layout.xml new file mode 100644 index 000000000..e51f7ec48 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/layout/settings_alexa_language_layout.xml @@ -0,0 +1,1535 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml similarity index 77% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml index 704697312..ef51070f7 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/navigation/settings_navigation.xml @@ -13,7 +13,13 @@ + android:label="@string/setting_alexa_language_title"> + + + + android:label="@string/setting_alexa_communication"> + android:label="@string/setting_alexa_communication"/> + + Alexa + [Acme Brandon]-Einstellungen + Amazon Alexa-Einstellungen + [Acme Brandon] aktivieren + Amazon Alexa aktivieren + Aktivierungswörter + Sagen Sie einfach „[Brandon]“ oder „Alexa“, um Unterstützung zu erhalten + [Brandon] und Alexa spielen einen Ton ab, wenn sie mit dem Zuhören beginnen + [Brandon] und Alexa spielen einen Ton ab, wenn sie das Zuhören beenden + Sprache + Push-to-Talk + Amazon Alexa + [Acme Brandon] + Teilen Sie den aktuellen Standort Ihres Fahrzeugs mit [Brandon] und Alexa, um so bessere Ergebnisse für Restaurants in der Nähe, das lokale Wetter und andere Anfragen zu erhalten. + Anmelden + Alexa Hands-free + Ton für den Start der Anfrage + Einen Ton abspielen, wenn Alexa mit dem Zuhören beginnt + Ton für das Ende der Anfrage + Einen Ton abspielen, wenn Alexa das Zuhören beendet + Alexa reagiert jedes Mal, wenn Sie „Alexa“ sagen + Standortfreigabe + Teilen Sie den aktuellen Standort Ihres Fahrzeugs mit Alexa, um so bessere Ergebnisse für Restaurants in der Nähe, das lokale Wetter und andere Anfragen zu erhalten. + Bitte nicht stören + Deaktiviert Benachrichtigungen + Kommunikation + Töne + Alexas Sprache + Abmelden + Alexa deaktivieren + Alexa Auto Client Service + Einstellungen + Abmelden? + Alexa deaktivieren? + Möchten Sie sich von Amazon Alexa abmelden? + ABMELDEN + ABBRECHEN + DEAKTIVIEREN + Alexa ist in diesem Fahrzeug dann nicht mehr verfügbar. + Grundeinstellungen außer Kraft setzen + Wenn diese Option ausgewählt wird, werden alle nachstehenden Einstellungen angewendet + Alexa-Gerät + Client-ID + Produkt-ID + Geräte-Seriennummer + Hersteller + AACS – Allgemein + AACS beim Booten des Geräts starten + AACS-Standardeinstelllungen + AACS-Audioeingang verwenden + AACS steuern + AACS NEU STARTEN UND KONFIGURATION ANWENDEN + AACS ABSCHALTEN + AACS STARTEN + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rAU/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 000000000..fc8f5821d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + [Acme Brandon] settings + Amazon Alexa settings + Enable [Acme Brandon] + Enable Amazon Alexa + Wake words + Get assistance by simply saying \"[Brandon]\" or \"Alexa\" + [Brandon] and Alexa play a sound when they start listening + [Brandon] and Alexa play a sound when they stop listening + Language + Push-to-talk + Amazon Alexa + [Acme Brandon] + Share your vehicle\'s current location with [Brandon] and Alexa to get better responses for nearby restaurants, local weather and more. + Sign in + Alexa Hands Free + Start of request sound + Play a sound when Alexa starts listening + End of request sound + Play a sound when Alexa stops listening + Alexa responds any time you say \"Alexa\" + Location sharing + Share your vehicle\'s current location with Alexa to get better responses for nearby restaurants, local weather and more. + Do Not Disturb + Disables notifications + Communication + Sounds + Alexa\'s language + Sign out + Disable Alexa + Alexa Auto Client Service + Settings + Sign out? + Disable Alexa? + Do you want to sign out of Amazon Alexa? + SIGN OUT + CANCEL + DISABLE + Alexa will no longer be available in this vehicle. + Override Base Configuration + All configurations below will be applied if this is selected + Alexa Device + Client ID + Product ID + Device Serial Number + Manufacturer + AACS General + Start AACS on Device Boot Up + AACS Defaults + Use AACS Audio Input + Control AACS + REBOOT AACS & APPLY CONFIGURATION + SHUT DOWN AACS + START AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rCA/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rCA/strings.xml new file mode 100644 index 000000000..fc8f5821d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rCA/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + [Acme Brandon] settings + Amazon Alexa settings + Enable [Acme Brandon] + Enable Amazon Alexa + Wake words + Get assistance by simply saying \"[Brandon]\" or \"Alexa\" + [Brandon] and Alexa play a sound when they start listening + [Brandon] and Alexa play a sound when they stop listening + Language + Push-to-talk + Amazon Alexa + [Acme Brandon] + Share your vehicle\'s current location with [Brandon] and Alexa to get better responses for nearby restaurants, local weather and more. + Sign in + Alexa Hands Free + Start of request sound + Play a sound when Alexa starts listening + End of request sound + Play a sound when Alexa stops listening + Alexa responds any time you say \"Alexa\" + Location sharing + Share your vehicle\'s current location with Alexa to get better responses for nearby restaurants, local weather and more. + Do Not Disturb + Disables notifications + Communication + Sounds + Alexa\'s language + Sign out + Disable Alexa + Alexa Auto Client Service + Settings + Sign out? + Disable Alexa? + Do you want to sign out of Amazon Alexa? + SIGN OUT + CANCEL + DISABLE + Alexa will no longer be available in this vehicle. + Override Base Configuration + All configurations below will be applied if this is selected + Alexa Device + Client ID + Product ID + Device Serial Number + Manufacturer + AACS General + Start AACS on Device Boot Up + AACS Defaults + Use AACS Audio Input + Control AACS + REBOOT AACS & APPLY CONFIGURATION + SHUT DOWN AACS + START AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rIN/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 000000000..fc8f5821d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + [Acme Brandon] settings + Amazon Alexa settings + Enable [Acme Brandon] + Enable Amazon Alexa + Wake words + Get assistance by simply saying \"[Brandon]\" or \"Alexa\" + [Brandon] and Alexa play a sound when they start listening + [Brandon] and Alexa play a sound when they stop listening + Language + Push-to-talk + Amazon Alexa + [Acme Brandon] + Share your vehicle\'s current location with [Brandon] and Alexa to get better responses for nearby restaurants, local weather and more. + Sign in + Alexa Hands Free + Start of request sound + Play a sound when Alexa starts listening + End of request sound + Play a sound when Alexa stops listening + Alexa responds any time you say \"Alexa\" + Location sharing + Share your vehicle\'s current location with Alexa to get better responses for nearby restaurants, local weather and more. + Do Not Disturb + Disables notifications + Communication + Sounds + Alexa\'s language + Sign out + Disable Alexa + Alexa Auto Client Service + Settings + Sign out? + Disable Alexa? + Do you want to sign out of Amazon Alexa? + SIGN OUT + CANCEL + DISABLE + Alexa will no longer be available in this vehicle. + Override Base Configuration + All configurations below will be applied if this is selected + Alexa Device + Client ID + Product ID + Device Serial Number + Manufacturer + AACS General + Start AACS on Device Boot Up + AACS Defaults + Use AACS Audio Input + Control AACS + REBOOT AACS & APPLY CONFIGURATION + SHUT DOWN AACS + START AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rUS/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 000000000..a7f4713ee --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,71 @@ + + Alexa + + + + [Acme Brandon] settings + Amazon Alexa settings + Enable [Acme Brandon] + Enable Amazon Alexa + Wake words + Get assistance by simply saying \"[Brandon]\" or \"Alexa\" + [Brandon] and Alexa play a sound when they start listening + [Brandon] and Alexa play a sound when they stop listening + Language + Push-to-talk + Amazon Alexa + [Acme Brandon] + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather and more. + + + + Sign in + Alexa Hands-Free + Start of request sound + Play a sound when Alexa starts listening + End of request sound + Play a sound when Alexa stops listening + Alexa responds any time you say \"Alexa\" + Location sharing + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Do Not Disturb + Disables notifications + Communication + Sounds + Alexa\'s language + Sign out + Disable Alexa + + + Alexa Auto Client Service + + Settings + Sign out? + Disable Alexa? + Do you want to sign out of Amazon Alexa? + SIGN OUT + CANCEL + DISABLE + Alexa will no longer be available in this vehicle. + + + Override Base Configuration + All configurations below will be applied if this is selected + + Alexa Device + Client Id + Product Id + Device Serial Number + Manufacturer + + AACS General + Start AACS on Device Bootup + + AACS Defaults + Use AACS Audio Input + + Control AACS + REBOOT AACS & APPLY CONFIGURATION + SHUTDOWN AACS + START AACS + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en/strings.xml new file mode 100644 index 000000000..fc8f5821d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-en/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + [Acme Brandon] settings + Amazon Alexa settings + Enable [Acme Brandon] + Enable Amazon Alexa + Wake words + Get assistance by simply saying \"[Brandon]\" or \"Alexa\" + [Brandon] and Alexa play a sound when they start listening + [Brandon] and Alexa play a sound when they stop listening + Language + Push-to-talk + Amazon Alexa + [Acme Brandon] + Share your vehicle\'s current location with [Brandon] and Alexa to get better responses for nearby restaurants, local weather and more. + Sign in + Alexa Hands Free + Start of request sound + Play a sound when Alexa starts listening + End of request sound + Play a sound when Alexa stops listening + Alexa responds any time you say \"Alexa\" + Location sharing + Share your vehicle\'s current location with Alexa to get better responses for nearby restaurants, local weather and more. + Do Not Disturb + Disables notifications + Communication + Sounds + Alexa\'s language + Sign out + Disable Alexa + Alexa Auto Client Service + Settings + Sign out? + Disable Alexa? + Do you want to sign out of Amazon Alexa? + SIGN OUT + CANCEL + DISABLE + Alexa will no longer be available in this vehicle. + Override Base Configuration + All configurations below will be applied if this is selected + Alexa Device + Client ID + Product ID + Device Serial Number + Manufacturer + AACS General + Start AACS on Device Boot Up + AACS Defaults + Use AACS Audio Input + Control AACS + REBOOT AACS & APPLY CONFIGURATION + SHUT DOWN AACS + START AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rMX/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 000000000..5f09c5f80 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Configuración de [Acme Brandon] + Configuración de Amazon Alexa + Activar [Acme Brandon] + Activar Amazon Alexa + Palabras de activación + Obtén ayuda con tan solo decir “[Brandon]” o “Alexa” + [Brandon] y Alexa emitirán un sonido cuando empiecen a escucharte + [Brandon] y Alexa emitirán un sonido cuando dejen de escucharte + Idioma + Presionar para realizar una solicitud + Amazon Alexa + [Acme Brandon] + Comparte la ubicación actual de tu vehículo con [Brandon] y Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + Iniciar sesión + Manos libres Alexa + Sonido del inicio de la solicitud + Reproduce un sonido cuando Alexa empieza a escucharte + Sonido del final de la solicitud + Reproduce un sonido cuando Alexa deja de escucharte + Alexa responderá cuando digas “Alexa” + Compartir ubicación + Comparte la ubicación actual de tu vehículo con Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + No molestar + Desactiva las notificaciones + Comunicación + Sonidos + Idioma de Alexa + Cerrar sesión + Desactivar Alexa + Servicio de atención al cliente de Alexa Auto + Configuración + ¿Quieres cerrar sesión? + ¿Quieres desactivar Alexa? + ¿Quieres cerrar la sesión de Amazon Alexa? + CERRAR SESIÓN + CANCELAR + DESACTIVAR + Alexa ya no estará disponible en este vehículo. + Anular configuración básica + Si seleccionas esta opción, las siguientes configuraciones se aplicarán + Dispositivo con Alexa + ID de cliente + ID de producto + Número de serie del dispositivo + Fabricante + AACS general + Iniciar AACS al arrancar el dispositivo + Configuración predeterminada de AACS + Usar entrada de audio de AACS + Control de AACS + REINICIAR AACS Y APLICAR CONFIGURACIÓN + APAGAR AACS + INICIAR AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rUS/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..5f09c5f80 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Configuración de [Acme Brandon] + Configuración de Amazon Alexa + Activar [Acme Brandon] + Activar Amazon Alexa + Palabras de activación + Obtén ayuda con tan solo decir “[Brandon]” o “Alexa” + [Brandon] y Alexa emitirán un sonido cuando empiecen a escucharte + [Brandon] y Alexa emitirán un sonido cuando dejen de escucharte + Idioma + Presionar para realizar una solicitud + Amazon Alexa + [Acme Brandon] + Comparte la ubicación actual de tu vehículo con [Brandon] y Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + Iniciar sesión + Manos libres Alexa + Sonido del inicio de la solicitud + Reproduce un sonido cuando Alexa empieza a escucharte + Sonido del final de la solicitud + Reproduce un sonido cuando Alexa deja de escucharte + Alexa responderá cuando digas “Alexa” + Compartir ubicación + Comparte la ubicación actual de tu vehículo con Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + No molestar + Desactiva las notificaciones + Comunicación + Sonidos + Idioma de Alexa + Cerrar sesión + Desactivar Alexa + Servicio de atención al cliente de Alexa Auto + Configuración + ¿Quieres cerrar sesión? + ¿Quieres desactivar Alexa? + ¿Quieres cerrar la sesión de Amazon Alexa? + CERRAR SESIÓN + CANCELAR + DESACTIVAR + Alexa ya no estará disponible en este vehículo. + Anular configuración básica + Si seleccionas esta opción, las siguientes configuraciones se aplicarán + Dispositivo con Alexa + ID de cliente + ID de producto + Número de serie del dispositivo + Fabricante + AACS general + Iniciar AACS al arrancar el dispositivo + Configuración predeterminada de AACS + Usar entrada de audio de AACS + Control de AACS + REINICIAR AACS Y APLICAR CONFIGURACIÓN + APAGAR AACS + INICIAR AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..d2530115d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-es/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Configuración de [Acme Brandon] + Configuración de Amazon Alexa + Activar [Acme Brandon] + Activar Amazon Alexa + Palabras de activación + Llama a \"[Brandon]\" o a \"Alexa\" para que te ayuden + [Brandon] y Alexa reproducen un sonido cuando comienzan a escuchar + [Brandon] y Alexa reproducen un sonido cuando deja de escuchar + Idioma + Pulsa y habla + Amazon Alexa + [Acme Brandon] + Comparte la ubicación actual de tu vehículo con [Brandon] y Alexa para recibir respuestas más precisas respecto a restaurantes cercanos, el tiempo local y más. + Iniciar sesión + Manos libres Alexa + Sonido de inicio de solicitud + Reproduce un sonido cuando Alexa empieza a escuchar + Sonido de fin de solicitud + Reproduce un sonido cuando Alexa deja de escuchar + Alexa responde cuando dices \"Alexa\" + Compartir ubicación + Comparte la ubicación actual de tu vehículo con Alexa para recibir respuestas más precisas respecto a restaurantes cercanos, el tiempo local y más. + No molestar + Desactiva las notificaciones + Comunicación + Sonidos + Idioma de Alexa + Cerrar sesión + Desactivar Alexa + Servicio de Atención al cliente de Alexa Auto + Configuración + ¿Cerrar sesión? + ¿Desactivar Alexa? + ¿Quieres cerrar la sesión de Amazon Alexa? + CERRAR SESIÓN + CANCELAR + DESACTIVAR + Alexa dejará de estar disponible en este vehículo. + Anular configuración de base + Si seleccionas esta opción, se aplicarán todas las configuraciones que se indican a continuación + Dispositivo Alexa + ID de cliente + ID de producto + Número de serie del dispositivo + Fabricante + AACS general + Iniciar AACS en el arranque del dispositivo + Valores predeterminados de AACS + Utilizar la entrada de audio AACS + Control de AACS + REINICIAR AACS Y APLICAR CONFIGURACIÓN + APAGAR AACS + INICIAR AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr-rCA/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000..d9bd5c670 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Paramètres [Acme Brandon] + Paramètres Amazon Alexa + Activer [Acme Brandon] + Activer Amazon Alexa + Mots d\'activation + Obtenez de l\'aide en disant simplement : « [Brandon] » ou « Alexa » + [Brandon] et Alexa joueront un son quand ils commenceront à écouter + [Brandon] et Alexa joueront un son quand ils arrêteront d\'écouter + Langue + Appuyer pour parler + Amazon Alexa + [Acme Brandon] + Partagez la localisation de votre véhicule avec [Brandon] et Alexa pour obtenir des réponses plus intelligentes sur les restaurants à proximité, la météo locale et plus encore. + Se connecter + Alexa mains libres + Son de début de requête + Jouer un son quand Alexa commence à écouter + Son de fin de requête + Jouer un son quand Alexa arrête d\'écouter + Alexa répond à chaque fois que vous dites : « Alexa » + Partage de la localisation + Partagez la localisation de votre véhicule avec Alexa pour obtenir des réponses plus intelligentes sur les restaurants à proximité, la météo locale et plus encore. + Ne pas déranger + Désactive les notifications + Communication + Sonneries + Langue d\'Alexa + Se déconnecter + Désactiver Alexa + Service à la clientèle Alexa Auto + Paramètres + Se déconnecter? + Désactiver Alexa? + Voulez-vous vous déconnecter d\'Amazon Alexa? + SE DÉCONNECTER + ANNULER + DÉSACTIVER + Alexa ne sera plus disponible dans ce véhicule. + Remplacer la configuration de base + Toutes les configurations ci-dessous seront appliquées si ceci est sélectionné + Appareil Alexa + ID du client + ID de produit + Numéro de série d\'appareil + Fabricant + AACS Général + Démarrer AACS au redémarrage de l\'appareil + Valeurs AACS par défaut + Utiliser l\'entrée audio AACS + Contrôle AACS + REDÉMARRAGE D\'AACS ET CONFIGURATION DE L\'APPLICATION + ÉTEINDRE AACS + DÉMARRER AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr/strings.xml new file mode 100644 index 000000000..96d560f5e --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-fr/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Paramètres [Acme Brandon] + Paramètres Amazon Alexa + Activer [Acme Brandon] + Activer Amazon Alexa + Mots d\'activation + Obtenez de l\'aide en disant simplement « [Brandon] » ou « Alexa » + [Brandon] et Alexa émettent un son lorsque l\'écoute commence + [Brandon] et Alexa émettent un son lorsque l\'écoute cesse + Langue + Appuyer pour parler + Amazon Alexa + [Acme Brandon] + Partagez la localisation actuelle de votre véhicule avec [Brandon] et Alexa pour obtenir des réponses plus pertinentes concernant les restaurants à proximité, la météo locale et bien plus encore. + Se connecter + Alexa mains-libres + Son de début de la requête + Un son est joué lorsqu\'Alexa comment à écouter + Son de fin de la requête + Un son est joué lorsqu\'Alexa cesse d\'écouter + Alexa répond à chaque fois que vous dites « Alexa » + Partage de localisation + Partagez la localisation actuelle de votre véhicule avec Alexa pour obtenir des réponses plus pertinentes concernant les restaurants à proximité, la météo locale et bien plus encore. + Ne pas déranger + Ce mode désactive les notifications + Communication + Sons + Langue d\'Alexa + Se déconnecter + Désactiver Alexa + Service client Alexa Auto + Paramètres + Se déconnecter ? + Désactiver Alexa ? + Voulez-vous vous déconnecter d\'Amazon Alexa ? + SE DÉCONNECTER + ANNULER + DÉSACTIVER + Alexa ne sera plus disponible dans ce véhicule. + Remplacer la configuration de base + Si cette option est sélectionnée, toutes les configurations ci-dessous seront appliquées + Appareil Alexa + Identifiant client + Identifiant produit + Numéro de série de l\'appareil + Fabricant + AACS général + Lancer AACS au démarrage de l\'appareil + AACS par défaut + Utiliser l\'entrée audio AACS + Contrôler AACS + REDÉMARRER AACS ET APPLIQUER LA CONFIGURATION + ARRÊTER AACS + LANCER AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-hi-rIN/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-hi-rIN/strings.xml new file mode 100644 index 000000000..b29f03dba --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-hi-rIN/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + [Acme Brandon] की सेटिंग + Amazon Alexa की सेटिंग + [Acme Brandon] को चालू करें + Amazon Alexa को चालू करें + वेक वर्ड + सिर्फ़ \"[Brandon]\" या \"Alexa\" बोलकर मदद पाएं + आवाज़ के बाद, [Brandon] और Alexa की ओर से सुनना शुरू किया जाता है + आवाज़ के बाद, [Brandon] और Alexa की ओर से सुनना बंद किया जाता है + भाषा + पुश-टू-टॉक + Amazon Alexa + [Acme Brandon] + आस-पास के रेस्टोरेंट, स्थानीय मौसम और कई दूसरी चीज़ों के बारे में बेहतर जवाब पाने के लिए, अपनी गाड़ी की मौजूदा लोकेशन को [Brandon] और Alexa के साथ शेयर करें. + साइन इन करें + Alexa हैंड्स-फ़्री + रीक्वेस्ट शुरू करने की आवाज़ + Alexa की ओर से सुनना शुरू करने पर आवाज़ चलाएं + रीक्वेस्ट पूरी होने की आवाज़ + Alexa की ओर से सुनना बंद कर देने पर आवाज़ चलाएं + आपके हर बार \"Alexa\" कहने पर Alexa की ओर से जवाब दिया जाएगा + लोकेशन शेयर करना + आस-पास के रेस्टोरेंट, स्थानीय मौसम और कई दूसरी चीज़ों के बारे में बेहतर जवाब पाने के लिए, अपनी गाड़ी की मौजूदा लोकेशन को Alexa के साथ शेयर करें. + परेशान न करें (डीएनडी) + इससे नोटिफ़िकेशन बंद हो जाएंगे + बातचीत + टोन और वॉल्यूम + Alexa की भाषा + साइन आउट करें + Alexa को बंद करें + Alexa Auto क्लाइंट सेवा + सेटिंग + साइन आउट करें? + Alexa को बंद करना है? + क्या आपको Amazon Alexa से साइन आउट करना है? + साइन आउट करें + कैंसिल करें + बंद करें + Alexa की सुविधा अब इस गाड़ी में उपलब्ध नहीं होगी. + बेस कॉन्फ़िगरेशन को ओवरराइड करें + अगर इसे चुना जाता है, तो नीचे दिए गए सभी कॉन्फ़िगरेशन लागू हो जाएंगे + Alexa डिवाइस + क्लाइंट की Id + प्रॉडक्ट की Id + डिवाइस का सीरियल नंबर + निर्माता + AACS सामान्य + डिवाइस के बूटअप पर AACS शुरू करें + AACS डिफ़ॉल्ट + AACS के ऑडियो इनपुट का इस्तेमाल करें + AACS को कंट्रोल करें + AACS को रीबूट करें और कॉन्फ़िगरेशन लागू करें + AACS को शट डाउन करें + AACS को शुरू करें + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-it/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-it/strings.xml new file mode 100644 index 000000000..c4beafc17 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-it/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Impostazioni [Acme Brandon] + Impostazioni Amazon Alexa + Attiva [Acme Brandon] + Attiva Amazon Alexa + Parole di attivazione + Per ricevere assistenza, puoi semplicemente dire \"[Brandon]\" o \"Alexa\" + [Brandon] e Alexa riproducono un suono quando iniziano ad ascoltare + [Brandon] e Alexa riproducono un suono quando smettono di ascoltare + Lingua + Premi-per-parlare + Amazon Alexa + [Acme Brandon] + Condividi la posizione attuale del tuo veicolo con [Brandon] e Alexa per ottenere risposte più pertinenti su ristoranti nelle vicinanze, il meteo locale e molto altro. + Accedi + Modalità A mani libere di Alexa + Suono di inizio richiesta + Riproduci un suono quando Alexa inizia ad ascoltare + Suono di fine richiesta + Riproduci un suono quando Alexa smette di ascoltare + Alexa risponderà ogni volta che dirai \"Alexa\" + Condivisione della posizione + Condividi la posizione attuale del tuo veicolo con Alexa per ottenere risposte più pertinenti su ristoranti nelle vicinanze, il meteo locale e molto altro. + Non disturbare + Disattiva le notifiche + Comunicazione + Suoni + La lingua di Alexa + Esci + Disattiva Alexa + Servizio client automatico Alexa + Impostazioni + Vuoi disconnetterti? + Disattivare Alexa? + Vuoi uscire da Amazon Alexa? + ESCI + ANNULLA + DISATTIVA + Alexa non sarà più disponibile in questo veicolo. + Sovrascrivi la configurazione di base + Selezionando questa opzione, saranno applicate tutte le configurazioni riportate di seguito + Dispositivo Alexa + ID cliente + ID prodotto + Numero di serie dispositivo + Produttore + AACS generale + Avvia AACS all\'avvio del dispositivo + Valori predefiniti AACS + Usa ingresso audio AACS + Controllo AACS + RIAVVIA AACS E APPLICA LA CONFIGURAZIONE + SPEGNIMENTO AACS + AVVIA AACS + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-ja/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-ja/strings.xml new file mode 100644 index 000000000..34c2439a9 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-ja/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + [Acme Brandon]の設定 + AmazonAlexaの設定 + [Acme Brandon]をオンにする + Amazon Alexaをオンにする + ウェイクワード + 音声アシスタントを使うには、「[Brandon]」または「アレクサ」と言ってください + [Brandon]とAlexaが聞き取りを開始するときにサウンドで知らせます。 + [Brandon]とAlexaが聞き取りを終了するときにサウンドで知らせます。 + 言語 + プッシュ・トゥ・トーク + Amazon Alexa + [Acme Brandon] + 車の位置情報へのアクセスを[Brandon]とAlexaに許可すると、最寄りのレストランや地域の天気予報など、状況に合った情報を得ることができます。 + サインイン + Alexaハンズフリー + リクエスト開始トーン + Alexaによる聞き取りの開始をサウンドで知らせます。 + リクエスト終了トーン + Alexaによる聞き取りの終了をサウンドで知らせます。 + 「アレクサ」と言うと、Alexaが返事をします。 + 位置情報の共有 + 車の位置情報へのアクセスをAlexaに許可すると、最寄りのレストランや地域の天気予報など、状況に合った情報を得ることができます。 + おやすみモード + 通知をオフにする + コミュニケーション + サウンド + Alexaの言語 + サインアウト + Alexaをオフにする + Alexa Autoクライアントサービス + 設定 + サインアウトしますか? + Alexaをオフにしますか? + Amazon Alexaからサインアウトしますか? + サインアウト + キャンセル + オフにする + 今後はこの車でAlexaを使用できなくなります。 + 基本設定の上書き + これを選択すると、以下のすべての設定が適用されます。 + Alexaデバイス + クライアントID + 製品ID + デバイスのシリアル番号 + 製造者 + AACS一般 + デバイス起動時にAACSを開始 + AACSのデフォルト設定 + AACSオーディオ入力を使用 + AACSを操作 + AACSを起動して設定を適用 + AACSをシャットダウン + AACSを開始 + diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values-pt-rBR/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000..d82e2e674 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,57 @@ + + + Alexa + Configurações do [Acme Brandon] + Configurações do Amazon Alexa + Ativar [Acme Brandon] + Ativar Amazon Alexa + Palavras de ativação + Receba assistência ao dizer simplesmente \"[Brandon]\" ou \"Alexa\" + O dispositivo [Brandon] e a Alexa reproduzem um som quando começam a escutar + O dispositivo [Brandon] e a Alexa reproduzem um som quando param de escutar + Idioma + Pressionar para falar + Amazon Alexa + [Acme Brandon] + Compartilhe a localização atual do seu veículo com o [Brandon] e a Alexa para obter respostas mais inteligentes para restaurantes nas proximidades, previsão do tempo local e muito mais. + Iniciar sessão + Alexa mãos livres + Início do som da solicitação + Reproduzir um som quando a Alexa começar a escutar + Fim do som da solicitação + Reproduzir um som quando a Alexa parar de escutar + A Alexa responde sempre que você disser: \"Alexa\" + Compartilhamento de localização + Compartilhe a localização atual do seu veículo com a Alexa para obter respostas mais inteligentes para restaurantes nas proximidades, previsão do tempo local e muito mais. + Não perturbe + Desativa notificações + Comunicação + Sons + Idioma da Alexa + Encerrar sessão + Desativar a Alexa + Serviço de atendimento ao cliente Alexa Auto + Configurações + Sair? + Desativar a Alexa? + Quer sair do Amazon Alexa? + ENCERRAR SESSÃO + CANCELAR + DESATIVAR + A Alexa não estará mais disponível neste veículo. + Substituir configuração básica + Todas as configurações abaixo serão aplicadas se esta opção estiver selecionada + Dispositivo Alexa + ID do cliente + ID do produto + Número de série do dispositivo + Fabricante + AACS geral + Iniciar o AACS na inicialização do dispositivo + Padrões do AACS + Usar entrada de áudio AACS + Controlar AACS + REINICIAR AACS E APLICAR CONFIGURAÇÃO + DESLIGAR AACS + LIGAR AACS + diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/values/dimens.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/values/dimens.xml diff --git a/aacs/android/app-components/alexa-auto-settings/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values/strings.xml new file mode 100644 index 000000000..a7f4713ee --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/values/strings.xml @@ -0,0 +1,71 @@ + + Alexa + + + + [Acme Brandon] settings + Amazon Alexa settings + Enable [Acme Brandon] + Enable Amazon Alexa + Wake words + Get assistance by simply saying \"[Brandon]\" or \"Alexa\" + [Brandon] and Alexa play a sound when they start listening + [Brandon] and Alexa play a sound when they stop listening + Language + Push-to-talk + Amazon Alexa + [Acme Brandon] + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather and more. + + + + Sign in + Alexa Hands-Free + Start of request sound + Play a sound when Alexa starts listening + End of request sound + Play a sound when Alexa stops listening + Alexa responds any time you say \"Alexa\" + Location sharing + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Do Not Disturb + Disables notifications + Communication + Sounds + Alexa\'s language + Sign out + Disable Alexa + + + Alexa Auto Client Service + + Settings + Sign out? + Disable Alexa? + Do you want to sign out of Amazon Alexa? + SIGN OUT + CANCEL + DISABLE + Alexa will no longer be available in this vehicle. + + + Override Base Configuration + All configurations below will be applied if this is selected + + Alexa Device + Client Id + Product Id + Device Serial Number + Manufacturer + + AACS General + Start AACS on Device Bootup + + AACS Defaults + Use AACS Audio Input + + Control AACS + REBOOT AACS & APPLY CONFIGURATION + SHUTDOWN AACS + START AACS + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/values/styles.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/values/styles.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/values/styles.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/values/styles.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/xml/aacs_preferences.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/xml/aacs_preferences.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/xml/aacs_preferences.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/xml/aacs_preferences.xml diff --git a/platforms/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml b/aacs/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml similarity index 88% rename from platforms/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml rename to aacs/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml index 88d128cfa..6ff9c4c62 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml +++ b/aacs/android/app-components/alexa-auto-settings/src/main/res/xml/alexa_preferences.xml @@ -37,6 +37,12 @@ app:summary="@string/setting_alexa_hands_free_summary" app:defaultValue="true" app:layout="@layout/alexa_preference_layout" /> + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragmentTest.java b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragmentTest.java new file mode 100644 index 000000000..eb27f7101 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/AlexaSoundPreferencesFragmentTest.java @@ -0,0 +1,120 @@ +package com.amazon.alexa.auto.settings; + +import android.content.Context; +import android.content.SharedPreferences; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentFactory; +import androidx.fragment.app.testing.FragmentScenario; +import androidx.preference.Preference; +import androidx.preference.SwitchPreferenceCompat; + +import com.amazon.alexa.auto.settings.config.PreferenceKeys; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.EARCON_SETTINGS; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.EARCON_SETTINGS_END; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.EARCON_SETTINGS_START; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +public class AlexaSoundPreferencesFragmentTest { + + @Mock + private Context mMockContext; + @Mock + private SharedPreferences mMockSharedPrefs; + @Mock + private SharedPreferences.Editor mMockEditor; + + @Before + public void setup() { + MockitoAnnotations.openMocks(this); + when(mMockContext.getSharedPreferences(EARCON_SETTINGS, 0)).thenReturn(mMockSharedPrefs); + when(mMockSharedPrefs.edit()).thenReturn(mMockEditor); + } + + @Test + public void testOnLoad_invokesSharesPrefsAndSetsValueInView() { + when(mMockSharedPrefs.getBoolean(EARCON_SETTINGS_START, true)).thenReturn(true); + when(mMockSharedPrefs.getBoolean(EARCON_SETTINGS_END, true)).thenReturn(true); + + launchFragment().onFragment(fragment -> { + SwitchPreferenceCompat soundStartPreference = fragment.getPreferenceScreen() + .findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_START); + SwitchPreferenceCompat soundEndPreference = fragment.getPreferenceScreen() + .findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_END); + Assert.assertNotNull(soundStartPreference); + Assert.assertNotNull(soundEndPreference); + + verify(mMockSharedPrefs).getBoolean(EARCON_SETTINGS_START, true); + verify(mMockSharedPrefs).getBoolean(EARCON_SETTINGS_END, true); + Assert.assertTrue(soundStartPreference.isChecked()); + Assert.assertTrue(soundEndPreference.isChecked()); + }); + } + + @Test + public void testOnEarconSettingDisableEnable_appropriateMethodIsInvoked() { + launchFragment().onFragment(fragment -> { + Preference preference = + fragment.getPreferenceScreen().findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_START); + Assert.assertNotNull(preference); + + preference.performClick(); + Mockito.verify(mMockEditor).putBoolean(EARCON_SETTINGS_START, true); + + preference.performClick(); + Mockito.verify(mMockEditor).putBoolean(EARCON_SETTINGS_START, false); + + preference = fragment.getPreferenceScreen().findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUND_END); + Assert.assertNotNull(preference); + + preference.performClick(); + Mockito.verify(mMockEditor).putBoolean(EARCON_SETTINGS_END, true); + + preference.performClick(); + Mockito.verify(mMockEditor).putBoolean(EARCON_SETTINGS_END, false); + }); + } + + private FragmentScenario launchFragment() { + return FragmentScenario.launchInContainer(AlexaSoundPreferencesFragmentOverride.class, null, + com.amazon.alexa.auto.apps.common.ui.R.style.Theme_Alexa_Standard, + new AlexaSoundPreferencesFragmentTest.AlexaSoundPreferencesFragmentFactory()); + } + + /** + * Override class under test to supply dependencies that are obtained using + * static methods. + */ + public static class AlexaSoundPreferencesFragmentOverride extends AlexaSoundPreferencesFragment { + @Override + void setDefaultPreferences() { + //Do nothing + } + } + + /** + * Fragment factory to inject mocks into Fragment. + */ + class AlexaSoundPreferencesFragmentFactory extends FragmentFactory { + @NonNull + @Override + public Fragment instantiate(@NonNull ClassLoader classLoader, @NonNull String className) { + AlexaSoundPreferencesFragmentOverride fragment = new AlexaSoundPreferencesFragmentOverride(); + fragment.mContext = mMockContext; + return fragment; + } + } +} diff --git a/platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java similarity index 94% rename from platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java rename to aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java index 9d2c6ada7..24f872a20 100644 --- a/platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java +++ b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AlexaSettingsHomeFragmentTest.java @@ -185,6 +185,21 @@ public void testOnLanguagePrefClickLanguageSettingsPageIsNavigated() { }); } + @Test + public void testOnSoundPrefClickSoundSettingsIsNavigated() { + setupPropMocks(true, true, null, null); + + launchFragment().onFragment(fragment -> { + Preference preference = + fragment.getPreferenceScreen().findPreference(PreferenceKeys.ALEXA_SETTINGS_SOUNDS); + Assert.assertNotNull(preference); + + preference.performClick(); + Mockito.verify(mMockNavController, Mockito.times(1)) + .navigate(R.id.navigation_fragment_alexa_settings_sounds); + }); + } + @Test public void testOnCommunicationPreferencePresents() { setupPropMocks(false, false, null, null); diff --git a/platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilderTest.java b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilderTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilderTest.java rename to aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/AuthSettingsScreenBuilderTest.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilderTest.java b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilderTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilderTest.java rename to aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/DebugSettingsScreenBuilderTest.java diff --git a/platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilderTest.java b/aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilderTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilderTest.java rename to aacs/android/app-components/alexa-auto-settings/src/test/java/com/amazon/alexa/auto/settings/home/VoiceAssistanceSettingsScreenBuilderTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/.gitignore b/aacs/android/app-components/alexa-auto-setup/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/.gitignore rename to aacs/android/app-components/alexa-auto-setup/.gitignore diff --git a/aacs/android/app-components/alexa-auto-setup/README.md b/aacs/android/app-components/alexa-auto-setup/README.md new file mode 100644 index 000000000..521ddb51d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/README.md @@ -0,0 +1,26 @@ +# Alexa Auto Setup +The following list describes the contents of this package: + +This package provides the UI for the setup workflow which includes login and subsequent setup steps. The UI is provided as Android ``Fragment``s along with ``View Model``s which can be used independently for building a different flavor of the UI. + +At present, this package provides UI/ViewModel for CBL (Code Based Linking) and Preview mode authentication. + +Note: For the app to work it must either be configured as a system app or app permissions need to be manually enabled by navigating to `Settings > Apps & Notifications > Show All Apps > com.amazon.alexaautoclientservice > Permissions > Enable Microphone` + +## Integration +### Gradle +Include the project with gradle. + +### Dependencies +Please refer to alexa-auto-apis doc to find details on how to fetch/publish dependencies. + +``CBLLoginViewModel`` needs access to following implementations (interfaces for them are defined in ``alexa-auto-apis`` package): +* ``AuthController``: This interface provides business logic for new authentication workflow. The interface must be made available from ``AlexaAppRootComponent``. +* ``LoginUIEventListener [Optional]``: This interface allows UI to let the observer know when login is finished. This event can be used by observer to progress the app UI to logged-in state. The interface should be made available through ``AlexaAppLoggedOutScopedComponent``, that should be made available through ``AlexaAppRootComponent#getScopedComponents()`` + +## Known Gaps +The setup flow in this app does satisfy CX requirements. Refer to HMI Guidelines - Setup section for guidance or work with your Amazon partner manager. + +### Missing Steps +* Navigation favorites upload permission +* Enable Push-to-talk permission \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/build.gradle b/aacs/android/app-components/alexa-auto-setup/build.gradle new file mode 100644 index 000000000..79c3869b8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/build.gradle @@ -0,0 +1,79 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + versionCode 1 + versionName "4.0" + vectorDrawables.useSupportLibrary = true + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-setup" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } +} + +dependencies { + implementation project(':aacscommonutils') + implementation project(':aacsconstants') + implementation project(':aacsipc') + + implementation project(":alexa-auto-apis") + implementation project(":alexa-auto-apps-common-ui") + implementation project(":alexa-auto-apps-common-util") + + implementation deps.google_zxing + implementation deps.androidx_appcompat + implementation deps.androidx_constraint + implementation deps.androidx_viewmodel + implementation deps.rxjava3 + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.androidx_arch_core_testing + testImplementation deps.androidx_fragment_testing + testImplementation deps.roboelectric + + // Navigation between UI components. + implementation deps.androidx_navigation_fragment + implementation deps.androidx_navigation_ui + + // Eventbus + implementation deps.eventbus + + // Dagger + api deps.dagger + kapt deps.dagger_compiler +} diff --git a/platforms/android/app-components/alexa-auto-lwa-auth/proguard-rules.pro b/aacs/android/app-components/alexa-auto-setup/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-lwa-auth/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-setup/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-setup/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/CBLLoginWorkflowSpecification.json b/aacs/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/CBLLoginWorkflowSpecification.json similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/CBLLoginWorkflowSpecification.json rename to aacs/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/CBLLoginWorkflowSpecification.json diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/PreviewModeLoginWorkflowSpecification.json b/aacs/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/PreviewModeLoginWorkflowSpecification.json similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/PreviewModeLoginWorkflowSpecification.json rename to aacs/android/app-components/alexa-auto-setup/src/main/assets/workflowSpecification/PreviewModeLoginWorkflowSpecification.json diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/AndroidModule.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/AndroidModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/AndroidModule.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/AndroidModule.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/ConfigModule.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/ConfigModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/ConfigModule.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/ConfigModule.java diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/SetupComponent.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/SetupComponent.java new file mode 100644 index 000000000..da6cda6e7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/SetupComponent.java @@ -0,0 +1,85 @@ +package com.amazon.alexa.auto.setup.dependencies; + +import com.amazon.alexa.auto.setup.workflow.AlexaSetupWorkflowControllerImpl; +import com.amazon.alexa.auto.setup.workflow.command.CheckLanguageCommand; +import com.amazon.alexa.auto.setup.workflow.command.CheckLocationConsentCommand; +import com.amazon.alexa.auto.setup.workflow.fragment.CBLViewModel; +import com.amazon.alexa.auto.setup.workflow.fragment.LanguageSelectionFragment; +import com.amazon.alexa.auto.setup.workflow.fragment.LocationConsentFragment; +import com.amazon.alexa.auto.setup.workflow.fragment.LoginFragment; +import com.amazon.alexa.auto.setup.workflow.fragment.CBLFragment; +import com.amazon.alexa.auto.setup.workflow.fragment.EnablePreviewModeFragment; + +import javax.inject.Singleton; + +import dagger.Component; + +/** + * Dagger Component for injecting Alexa Setup Dependencies. + */ +@Component(modules = {WorkflowModule.class, AndroidModule.class, ConfigModule.class}) +@Singleton +public interface SetupComponent { + /** + * Inject dependencies for @c WorkflowController. + * + * @param workflowController workflow controller where dependencies are injected. + */ + void injectWorkflowController(AlexaSetupWorkflowControllerImpl workflowController); + + /** + * Inject dependencies for @c LanguageSelectionFragment. + * + * @param languageSelectionFragment language selection fragment where dependencies are injected. + */ + void injectLanguageSettingsFragment(LanguageSelectionFragment languageSelectionFragment); + + /** + * Inject dependencies for @c CheckLanguageCommand. + * + * @param checkLanguageCommand check language command where dependencies are injected. + */ + void injectCheckLanguageCommand(CheckLanguageCommand checkLanguageCommand); + + /** + * Inject dependencies for @c CheckLocationConsentCommand. + * + * @param checkLocationConsentCommand check location command where dependencies are injected. + */ + void injectCheckLocationConsentCommand(CheckLocationConsentCommand checkLocationConsentCommand); + + /** + * Inject dependencies for @c LocationConsentFragment. + * + * @param locationConsentFragment Location fragment where dependencies are injected. + */ + void injectLocationConsentFragment(LocationConsentFragment locationConsentFragment); + + /** + * Inject dependencies for @c CBLViewModel. + * + * @param cblViewModel CBL View Model where dependencies are injected. + */ + void injectCBLViewModel(CBLViewModel cblViewModel); + + /** + * Inject dependencies for @c CBLFragment. + * + * @param cblFragment CBLFragment where dependencies are injected. + */ + void injectCBLFragment(CBLFragment cblFragment); + + /** + * Inject dependencies for @c EnablePreviewModeFragment. + * + * @param enablePreviewModeFragment where dependencies are injected. + */ + void injectEnablePreviewModeFragment(EnablePreviewModeFragment enablePreviewModeFragment); + + /** + * Inject dependencies for @c LoginFragment. + * + * @param loginFragment LoginFragment where dependencies are injected. + */ + void injectLoginFragment(LoginFragment loginFragment); +} diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/WorkflowModule.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/WorkflowModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/WorkflowModule.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/dependencies/WorkflowModule.java diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/receiver/NetworkStateChangeReceiver.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/receiver/NetworkStateChangeReceiver.java new file mode 100644 index 000000000..8b5006dc2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/receiver/NetworkStateChangeReceiver.java @@ -0,0 +1,45 @@ +package com.amazon.alexa.auto.setup.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.amazon.alexa.auto.apis.app.AlexaApp; +import com.amazon.alexa.auto.apps.common.util.ModuleProvider; +import com.amazon.alexa.auto.apps.common.util.NetworkUtil; +import com.amazon.alexa.auto.setup.workflow.WorkflowMessage; +import com.amazon.alexa.auto.setup.workflow.event.LoginEvent; + +import org.greenrobot.eventbus.EventBus; + +import static com.amazon.aacsconstants.NetworkConstants.ANDROID_CONNECTIVITY_CHANGE_ACTION; +import static com.amazon.alexa.auto.apps.common.util.ModuleProvider.ModuleName.LVC; +import static com.amazon.alexa.auto.apps.common.util.NetworkUtil.TYPE_NOT_CONNECTED; + +/** + * Receives changes to network state and publishes appropriate events + */ +public class NetworkStateChangeReceiver extends BroadcastReceiver { + private static final String TAG = NetworkStateChangeReceiver.class.getSimpleName(); + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceived"); + if (AlexaApp.from(context).getRootComponent().getAlexaSetupController().isSetupCompleted()) { + return; + } else if (ModuleProvider.containsModule(context, LVC) + && AlexaApp.from(context).getRootComponent().getAuthController().isAuthenticated()) { + return; + } + if (ANDROID_CONNECTIVITY_CHANGE_ACTION.equals(intent.getAction())) { + int connectivityStatus = NetworkUtil.getConnectivityStatus(context); + if (connectivityStatus == TYPE_NOT_CONNECTED) { + EventBus.getDefault().post(new WorkflowMessage(LoginEvent.NETWORK_DISCONNECTED_EVENT)); + } else if (connectivityStatus == NetworkUtil.TYPE_WIFI + || connectivityStatus == NetworkUtil.TYPE_MOBILE) { + EventBus.getDefault().post(new WorkflowMessage(LoginEvent.NETWORK_CONNECTED_EVENT)); + } + } + } +} diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/AlexaSetupWorkflowControllerImpl.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/AlexaSetupWorkflowControllerImpl.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/AlexaSetupWorkflowControllerImpl.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/AlexaSetupWorkflowControllerImpl.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/Workflow.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/Workflow.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/Workflow.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/Workflow.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowMessage.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowMessage.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowMessage.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowMessage.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigator.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigator.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigator.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigator.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowProvider.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowProvider.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowProvider.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowProvider.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowStep.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowStep.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowStep.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/WorkflowStep.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckContactsConsentStatusCommand.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckContactsConsentStatusCommand.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckContactsConsentStatusCommand.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckContactsConsentStatusCommand.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLanguageCommand.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLanguageCommand.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLanguageCommand.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLanguageCommand.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommand.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommand.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommand.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommand.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java similarity index 97% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java index ae01419e5..9a2ee70dd 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckLoginRequiredCommand.java @@ -27,7 +27,7 @@ public void execute() { if (authController.isAuthenticated()) { if (authController.getAuthMode() == AuthMode.AUTH_PROVIDER_AUTHORIZATION) { publishEvent(new WorkflowMessage(LoginEvent.PREVIEW_MODE_ENABLED)); - } else if (authController.getAuthMode() == AuthMode.AUTH_PROVIDER_AUTHORIZATION) { + } else if (authController.getAuthMode() == AuthMode.CBL_AUTHORIZATION) { publishEvent(new WorkflowMessage(LoginEvent.CBL_AUTH_FINISHED)); } } else { diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckNetworkStatusCommand.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckNetworkStatusCommand.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckNetworkStatusCommand.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/CheckNetworkStatusCommand.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/Command.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/Command.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/Command.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/Command.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommand.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommand.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommand.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommand.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/LoginEvent.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/LoginEvent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/LoginEvent.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/LoginEvent.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/VoiceAssistanceEvent.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/VoiceAssistanceEvent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/VoiceAssistanceEvent.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/event/VoiceAssistanceEvent.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java similarity index 84% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java index f0e77dfef..3c20aa77a 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragment.java @@ -3,6 +3,7 @@ import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.os.Bundle; +import android.os.LocaleList; import android.text.Html; import android.text.Spanned; import android.view.LayoutInflater; @@ -11,6 +12,7 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,9 +30,16 @@ import com.amazon.alexa.auto.setup.workflow.WorkflowMessage; import com.amazon.alexa.auto.setup.workflow.event.LoginEvent; import com.amazon.alexa.auto.setup.workflow.util.QRCodeGenerator; +import com.amazon.alexa.auto.setup.dependencies.AndroidModule; +import com.amazon.alexa.auto.setup.dependencies.DaggerSetupComponent; +import com.amazon.alexa.auto.apps.common.util.config.AlexaPropertyManager; +import javax.inject.Inject; import org.greenrobot.eventbus.EventBus; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; +import static com.amazon.alexa.auto.apps.common.util.LocaleUtil.getLocalizedDomain; + /** * Fragment for CBL display screen. */ @@ -41,6 +50,9 @@ public class CBLFragment extends Fragment { QRCodeGenerator mQRCodeGenerator; NavController mNavController; + @Inject + AlexaPropertyManager mAlexaPropertyManager; + /** * Constructs an instance of CBLFragment. */ @@ -64,6 +76,13 @@ public CBLFragment() { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (mAlexaPropertyManager == null) { + DaggerSetupComponent.builder() + .androidModule(new AndroidModule(getContext())) + .build() + .injectCBLFragment(this); + } + if (mViewModel == null) { // It would be non-null for test injected dependencies. mViewModel = new ViewModelProvider(this).get(CBLViewModel.class); } @@ -117,6 +136,13 @@ private void authWorkflowStateChanged(AuthWorkflowData loginData) { updateQRCodeContainerVisibility(View.GONE); updateVisibilitySpinner(View.GONE); updateLoginInContainerVisibility(View.GONE); + mAlexaPropertyManager.updateAlexaProperty(WAKEWORD_ENABLED, "true") + .doOnSuccess((succeeded) -> { + if (!succeeded) { + Log.d(TAG, " Wakeword enable failed "); + } + }) + .subscribe(); EventBus.getDefault().post(new WorkflowMessage(LoginEvent.CBL_AUTH_FINISHED)); break; case CBL_Auth_Start_Failed: @@ -176,6 +202,7 @@ private void setContentForCBLViewTitle() { // Make multicolor text for title. TextView titleTextView = view.findViewById(R.id.qr_code_title_textview); String titleText = getResources().getString(R.string.login_qr_code_message); + titleText = String.format(titleText, getLocalizedDomain(LocaleList.getDefault().get(0)) + "/code"); Spanned spanned = Html.fromHtml(titleText, Html.FROM_HTML_MODE_COMPACT); titleTextView.setText(spanned); } diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java similarity index 90% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java index f281c35a3..c94d66271 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModel.java @@ -1,6 +1,7 @@ package com.amazon.alexa.auto.setup.workflow.fragment; import android.app.Application; +import android.content.Context; import android.os.Handler; import android.util.Log; @@ -27,6 +28,8 @@ import io.reactivex.rxjava3.disposables.Disposable; +import static com.amazon.alexa.auto.apps.common.util.DNDSettingsProvider.resetDNDSetting; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.resetEarconSettings; import static com.amazon.alexa.auto.setup.workflow.model.LocationConsent.DISABLED; /** @@ -92,9 +95,9 @@ public LiveData loginWorkflowState() { public void startLogin() { Log.d(TAG, "CBL Workflow starting"); - // Resetting location consent to DISABLED to clear out existing state (e.g. it's possible + // Resetting the current user's preferences to clear out existing state (e.g. it's possible // that previously the user had enabled preview mode and enabled location consent) - resetLocationConsent(); + resetUserPreferences(getApplication().getApplicationContext()); // Make sure to cancel the login with auth provider, before we start CBL login flow. mAuthController.cancelLogin(AuthMode.AUTH_PROVIDER_AUTHORIZATION); @@ -111,11 +114,21 @@ public void startLogin() { }); } + /** + * Resets user preferences to default + * @param context + */ + private void resetUserPreferences(Context context) { + resetEarconSettings(context); + resetLocationConsent(context); + resetDNDSetting(context); + } + /** * Reset location consent to default value: DISABLED when the user logs out */ - public void resetLocationConsent() { - String extraModules = ModuleProvider.getModules(getApplication().getApplicationContext()); + public void resetLocationConsent(Context context) { + String extraModules = ModuleProvider.getModules(context); if (extraModules.contains(ModuleProvider.ModuleName.GEOLOCATION.name())) { mAlexaPropertyManager.updateAlexaProperty(AACSPropertyConstants.GEOLOCATION_ENABLED, DISABLED.getValue()) .doOnSuccess((succeeded) -> { diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragment.java new file mode 100644 index 000000000..9ae0203b1 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragment.java @@ -0,0 +1,159 @@ +package com.amazon.alexa.auto.setup.workflow.fragment; + +import android.graphics.Color; +import android.os.Bundle; +import android.os.LocaleList; +import android.text.Annotation; +import android.text.SpannedString; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; + +import com.amazon.alexa.auto.apis.auth.AuthWorkflowData; +import com.amazon.alexa.auto.setup.R; +import com.amazon.alexa.auto.setup.workflow.WorkflowMessage; +import com.amazon.alexa.auto.setup.workflow.event.LoginEvent; +import com.amazon.alexa.auto.setup.dependencies.AndroidModule; +import com.amazon.alexa.auto.setup.dependencies.DaggerSetupComponent; +import com.amazon.alexa.auto.apps.common.util.config.AlexaPropertyManager; +import javax.inject.Inject; + +import org.greenrobot.eventbus.EventBus; + +import static com.amazon.alexa.auto.app.common.util.PopupDialogUtil.embedUrlInPopupDialog; +import static com.amazon.alexa.auto.app.common.util.ViewUtils.toggleViewVisibility; +import static com.amazon.alexa.auto.setup.workflow.event.LoginEvent.SETUP_ERROR; +import static com.amazon.alexa.auto.apps.common.util.LocaleUtil.getLocalizedDomain; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; + +/** + * Fragment for enabling Preview Mode + */ +public class EnablePreviewModeFragment extends Fragment { + private static final String TAG = EnablePreviewModeFragment.class.getSimpleName(); + + private static final String CONDITIONS_OF_USE_URL = + "https://www.%s/gp/help/customer/display.html?nodeId=201909000&pop-up=1"; + private static final String TERMS_OF_USE_URL = + "https://www.%s/gp/help/customer/display.html?nodeId=201566380&pop-up=1"; + private static final String PRIVACY_INFO_URL + = "https://www.%s/gp/help/customer/display.html?nodeId=468496&pop-up=1"; + + private EnablePreviewModeViewModel mViewModel; + + @Inject + AlexaPropertyManager mAlexaPropertyManager; + + /** + * Constructs an instance of EnablePreviewModeFragment. + */ + public EnablePreviewModeFragment() {} + + @VisibleForTesting + EnablePreviewModeFragment(@NonNull EnablePreviewModeViewModel mViewModel) { + this.mViewModel = mViewModel; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (mAlexaPropertyManager == null) { + DaggerSetupComponent.builder() + .androidModule(new AndroidModule(getContext())) + .build() + .injectEnablePreviewModeFragment(this); + } + mViewModel = mViewModel == null + ? new ViewModelProvider(this).get(EnablePreviewModeViewModel.class) + : mViewModel; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.enable_preview_mode, container, false); + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mViewModel.loginWorkflowState().observe(getViewLifecycleOwner(), this::authWorkflowStateChanged); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + View fragmentView = requireView(); + + TextView enablePreviewModeButton = fragmentView.findViewById(R.id.enable_preview_mode_action_button); + enablePreviewModeButton.setOnClickListener(view -> mViewModel.enablePreviewMode()); + + TextView enablePreviewModeDisclaimer = fragmentView.findViewById(R.id.enable_preview_mode_disclaimer); + SpannedString spannedString = new SpannedString(getText(R.string.enable_preview_mode_disclaimer)); + Annotation[] spans = spannedString.getSpans(0, spannedString.length(), Annotation.class); + + if (spans.length > 0) { + embedUrlInPopupDialog(getContext(), + enablePreviewModeDisclaimer, + spannedString.getSpanStart(spans[0]), + spannedString.getSpanEnd(spans[0]), + String.format(CONDITIONS_OF_USE_URL, getLocalizedDomain(LocaleList.getDefault().get(0))), + Color.CYAN); + + embedUrlInPopupDialog(getContext(), + enablePreviewModeDisclaimer, + spannedString.getSpanStart(spans[1]), + spannedString.getSpanEnd(spans[1]), + String.format(TERMS_OF_USE_URL, getLocalizedDomain(LocaleList.getDefault().get(0))), + Color.CYAN); + + embedUrlInPopupDialog(getContext(), + enablePreviewModeDisclaimer, + spannedString.getSpanStart(spans[2]), + spannedString.getSpanEnd(spans[2]), + String.format(PRIVACY_INFO_URL, getLocalizedDomain(LocaleList.getDefault().get(0))), + Color.CYAN); + } + } + + private void authWorkflowStateChanged(AuthWorkflowData loginData) { + switch (loginData.getAuthState()) { + case Auth_Provider_Auth_Started: + updateSpinnerVisibility(View.VISIBLE); + break; + case Auth_Provider_Authorized: + mAlexaPropertyManager.updateAlexaProperty(WAKEWORD_ENABLED, "true") + .doOnSuccess((succeeded) -> { + if (!succeeded) { + Log.d(TAG, " Wakeword disable failed "); + } + }) + .subscribe(); + EventBus.getDefault().post(new WorkflowMessage(LoginEvent.PREVIEW_MODE_ENABLED)); + break; + case Auth_Provider_Authorization_Error: + EventBus.getDefault().post(new WorkflowMessage(SETUP_ERROR)); + break; + } + } + + private void updateSpinnerVisibility(int visible) { + View view = requireView(); + ProgressBar spinner = view.findViewById(R.id.enable_preview_mode_progress_spinner); + spinner.setVisibility(visible); + TextView enablePreviewModeButton = view.findViewById(R.id.enable_preview_mode_action_button); + toggleViewVisibility(enablePreviewModeButton, visible); + } +} + diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeViewModel.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeViewModel.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeViewModel.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeViewModel.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java similarity index 86% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java index a0abbfac4..71c4439e9 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java +++ b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragment.java @@ -6,16 +6,17 @@ import android.graphics.PorterDuff; import android.os.Bundle; import android.os.Handler; +import android.os.LocaleList; import android.os.Looper; import android.text.Html; import android.text.Spanned; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -35,11 +36,17 @@ import com.amazon.alexa.auto.setup.workflow.WorkflowMessage; import com.amazon.alexa.auto.setup.workflow.event.LoginEvent; import com.amazon.alexa.auto.setup.workflow.util.QRCodeGenerator; +import com.amazon.alexa.auto.setup.dependencies.AndroidModule; +import com.amazon.alexa.auto.setup.dependencies.DaggerSetupComponent; +import com.amazon.alexa.auto.apps.common.util.config.AlexaPropertyManager; +import javax.inject.Inject; import org.greenrobot.eventbus.EventBus; import static com.amazon.alexa.auto.app.common.util.ViewUtils.toggleViewVisibility; import static com.amazon.alexa.auto.setup.workflow.event.LoginEvent.SETUP_ERROR; +import static com.amazon.alexa.auto.apps.common.util.LocaleUtil.getLocalizedDomain; +import static com.amazon.aacsconstants.AACSPropertyConstants.WAKEWORD_ENABLED; /** * Fragment for displaying Login screen and different options to login. @@ -53,6 +60,9 @@ public class LoginFragment extends Fragment { NavController mNavController; private Handler mHandler; + @Inject + AlexaPropertyManager mAlexaPropertyManager; + /** * Constructs an instance of LoginFragment. */ @@ -80,6 +90,13 @@ public LoginFragment() { public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (mAlexaPropertyManager == null) { + DaggerSetupComponent.builder() + .androidModule(new AndroidModule(getContext())) + .build() + .injectLoginFragment(this); + } + if (mViewModel == null) { // It would be non-null for test injected dependencies. mViewModel = new ViewModelProvider(this).get(LoginViewModel.class); } @@ -111,8 +128,6 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - setContentForCBLViewTitle(); - View fragmentView = requireView(); mNavController = findNavController(fragmentView); @@ -130,7 +145,7 @@ public void onActivityCreated(Bundle savedInstanceState) { updateSpinnerVisibility(View.VISIBLE); Handler handler = new Handler(); handler.postDelayed(() -> - mNavController.navigate(R.id.navigation_fragment_enablePreviewMode), + mNavController.navigate(R.id.navigation_fragment_enablePreviewMode), 2000); }); } @@ -139,6 +154,7 @@ public void onActivityCreated(Bundle savedInstanceState) { private void authWorkflowStateChanged(AuthWorkflowData loginData) { switch (loginData.getAuthState()) { case CBL_Auth_Started: + setContentForCBLViewTitle(); updateQRCodeContainerVisibility(View.GONE); updateSpinnerVisibility(View.VISIBLE); updateLoginInContainerVisibility(View.VISIBLE); @@ -152,6 +168,13 @@ private void authWorkflowStateChanged(AuthWorkflowData loginData) { updateCBLCodePair(loginData.getCodePair()); break; case CBL_Auth_Finished: + mAlexaPropertyManager.updateAlexaProperty(WAKEWORD_ENABLED, "true") + .doOnSuccess((succeeded) -> { + if (!succeeded) { + Log.d(TAG, " Wakeword disable failed "); + } + }) + .subscribe(); EventBus.getDefault().post(new WorkflowMessage(LoginEvent.CBL_AUTH_FINISHED)); break; case CBL_Auth_Start_Failed: @@ -212,6 +235,7 @@ private void setContentForCBLViewTitle() { // Make multicolor text for title. TextView titleTextView = view.findViewById(R.id.qr_code_title_textview); String titleText = getResources().getString(R.string.login_qr_code_message); + titleText = String.format(titleText, getLocalizedDomain(LocaleList.getDefault().get(0)) + "/code"); Spanned spanned = Html.fromHtml(titleText, Html.FROM_HTML_MODE_COMPACT); titleTextView.setText(spanned); } diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModel.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModel.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModel.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModel.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkViewModel.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkViewModel.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkViewModel.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkViewModel.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragment.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragment.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragment.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragment.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/model/LocationConsent.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/model/LocationConsent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/model/LocationConsent.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/model/LocationConsent.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/QRCodeGenerator.java b/aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/QRCodeGenerator.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/QRCodeGenerator.java rename to aacs/android/app-components/alexa-auto-setup/src/main/java/com/amazon/alexa/auto/setup/workflow/util/QRCodeGenerator.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/drawable/ic_wifi_help.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/drawable/ic_wifi_help.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/drawable/ic_wifi_help.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/drawable/ic_wifi_help.xml diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/auth_provider_login_finished.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/auth_provider_login_finished.xml new file mode 100644 index 000000000..3503ac89c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/auth_provider_login_finished.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_code_loading.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_code_loading.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_code_loading.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_code_loading.xml diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_error.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_error.xml new file mode 100644 index 000000000..03787ffd1 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_error.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_finished.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_finished.xml new file mode 100644 index 000000000..ce5f1aad9 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/cbl_login_finished.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/enable_preview_mode.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/enable_preview_mode.xml new file mode 100644 index 000000000..edc1f1908 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/enable_preview_mode.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/location_consent.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/location_consent.xml new file mode 100644 index 000000000..4f342876f --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/location_consent.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_display_cbl_code.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_display_cbl_code.xml new file mode 100644 index 000000000..aa5498df3 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_display_cbl_code.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_start.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_start.xml new file mode 100644 index 000000000..6d3e50d72 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/login_start.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/network_fragment.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/network_fragment.xml new file mode 100644 index 000000000..ed1cb0ff2 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/network_fragment.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/setup_not_complete.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/setup_not_complete.xml new file mode 100644 index 000000000..fe09b475a --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/setup_not_complete.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/start_language_selection.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/start_language_selection.xml new file mode 100644 index 000000000..d28a35c81 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout-land/start_language_selection.xml @@ -0,0 +1,55 @@ + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/layout/aacs_connection_loading.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/aacs_connection_loading.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/layout/aacs_connection_loading.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/layout/aacs_connection_loading.xml diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/auth_provider_login_finished.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/auth_provider_login_finished.xml new file mode 100644 index 000000000..46c9795a3 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/auth_provider_login_finished.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_code_loading.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_code_loading.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_code_loading.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_code_loading.xml diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_fragment.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_fragment.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_fragment.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_fragment.xml diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_error.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_error.xml new file mode 100644 index 000000000..818749699 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_error.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_finished.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_finished.xml new file mode 100644 index 000000000..71b82485d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/cbl_login_finished.xml @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/enable_preview_mode.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/enable_preview_mode.xml new file mode 100644 index 000000000..61043b5cf --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/enable_preview_mode.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/location_consent.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/location_consent.xml new file mode 100644 index 000000000..4f342876f --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/location_consent.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_display_cbl_code.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_display_cbl_code.xml new file mode 100644 index 000000000..257001996 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_display_cbl_code.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/layout/login_fragment.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_fragment.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/layout/login_fragment.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_fragment.xml diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_start.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_start.xml new file mode 100644 index 000000000..6d3e50d72 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/login_start.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/network_fragment.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/network_fragment.xml new file mode 100644 index 000000000..3fab2d52b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/network_fragment.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/setup_not_complete.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/setup_not_complete.xml new file mode 100644 index 000000000..15eb49fb6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/setup_not_complete.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/start_language_selection.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/start_language_selection.xml new file mode 100644 index 000000000..ebab6921b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/layout/start_language_selection.xml @@ -0,0 +1,54 @@ + + + + + + + + + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml similarity index 97% rename from platforms/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml rename to aacs/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml index 4eceafdd7..095814b2d 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/navigation/setup_navigation.xml @@ -19,7 +19,7 @@ + android:label="@string/setting_alexa_language_title"/> + + + %1$s an. Geben Sie dann folgenden Code ein: + ]]> + + ALEXA AUSPROBIEREN + Datenschutzerklärung + Nutzungsbedingungen + Erneut versuchen + ANMELDEN + SPÄTER ANMELDEN + Bitte warten Sie, bis die Verbindung mit AACS hergestellt wurde … + Machen Sie das Beste aus Ihrer Autofahrt – ganz einfach per Sprachbefehl. Alexa liefert Wegbeschreibungen, spielt Musik, tätigt Anrufe und vieles mehr. + Alexa ohne Anmeldung aktivieren? + ZUSTIMMEN UND ALEXA AKTIVIEREN + Sie können Alexa trotzdem für Dinge wie Informationen und Wegbeschreibungen verwenden. Melden sie sich an, um Musik zu hören und Wettervorhersagen, Smart Home-Funktionen und vieles mehr zu nutzen. + Amazon verarbeitet und speichert Alexa-Interaktionen und andere Daten in der Cloud, um Dienste bereitzustellen und zu verbessern. Durch die Auswahl von „Zustimmen und aktivieren“ stimmen Sie den Nutzungsbedingungen von Amazon sowie allen hier aufgeführten Bestimmungen zu. \n\n Erfahren Sie, wie Alexa Datenschutz gewährleistet. + Bei der Aktivierung des Vorschaumodus ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut. + Oder scannen Sie diesen Code: + Fertig, %1$s! + Versuchen Sie Folgendes: + NETZWERKEINSTELLUNGEN + Netzwerkfehler + Alexa muss auf das Internet zugreifen können, um die Einrichtung abzuschließen. \n Überprüfen Sie bitte Ihre Netzwerkverbindung und versuchen Sie es dann erneut. + Melden Sie sich bei Ihrem Amazon-Konto an + „Alexa, stell die Temperatur auf 22 Grad.“ + „Alexa, such ein Café.“ + „Alexa, spiel Musik.“ + „Alexa, stell die Temperatur auf 22 Grad.“ + „Alexa, bring mich zum Flughafen.“ + „Alexa, schalte auf 88,5 FM.“ + Melden Sie sich für Musik, Wettervorhersagen, Smart Home-Funktionen und vieles mehr an. + FERTIG + Alexas Sprache + SPRACHE AUSWÄHLEN + Alexa ist nicht auf %1$s verfügbar. Wählen Sie eine Sprache für Alexa. + WEITER + Etwas ist schiefgelaufen + Bei der Einrichtung von Alexa ist ein Problem aufgetreten. Bitte versuchen Sie es erneut. + Bei der Einrichtung ist ein Problem aufgetreten. Bitte versuchen Sie es erneut. + Bei der Anmeldung ist ein Problem aufgetreten. Bitte versuchen Sie es erneut. + ERNEUT VERSUCHEN + ÜBERSPRINGEN + STANDORT VERWENDEN + Was ist in der Nähe? + Teilen Sie den aktuellen Standort Ihres Fahrzeugs mit Alexa, um so bessere Ergebnisse für Restaurants in der Nähe, das lokale Wetter und andere Anfragen zu erhalten. + Teilen Sie den aktuellen Standort Ihres Fahrzeugs mit [Brandon] und Alexa, um so bessere Ergebnisse für Restaurants in der Nähe, das lokale Wetter und andere Anfragen zu erhalten. + „Alexa, finde Restaurants in der Nähe.“ + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rAU/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rAU/strings.xml new file mode 100644 index 000000000..12419524d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rAU/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s and sign in. Then enter this code: + ]]> + + TRY ALEXA + Privacy Notice + Terms of Use + Try Again + SIGN IN + SIGN IN LATER + Please wait. Connecting to AACS… + Use voice to make the most of your drive. Alexa can help with directions, music, calls and much more. + Enable Alexa without sign in? + AGREE & ENABLE ALEXA + You can still talk to Alexa for things like information and getting directions. For music, weather, smart home and more, sign in. + Amazon processes and retains Alexa interactions and other data in the cloud to provide and improve our services. By selecting \“Agree & Enable Alexa\“ you accept Amazon\’s Conditions of Use and all the terms found here. \n\n Learn how Alexa is designed to protect your privacy. + There was an issue enabling Preview mode. Please try again. + Or scan this code: + You\'re all done%1$s! + Try: + NETWORK SETTINGS + Network Error + Alexa needs access to the internet to complete setup. \n Please check your network connection and try again. + Sign in to your Amazon account + \"Alexa, set the temperature to 22\" + \"Alexa, find a café\" + \"Alexa, play music\" + \"Alexa, set the temperature to 22\" + \"Alexa, take me to the airport\" + \"Alexa, tune in to 88.5 FM\" + For music, weather, smart home and more, sign in. + DONE + Alexa\'s language + SELECT LANGUAGE + Alexa isn\'t available in %1$s. Select a language for Alexa. + CONTINUE + Something\'s gone wrong + There was an issue setting up Alexa. Please try again. + There was an issue setting up. Please try again. + There was an issue signing in. Please try again. + TRY AGAIN + SKIP + USE LOCATION + What\'s nearby? + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather and more. + \"Alexa, find restaurants near me\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rCA/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rCA/strings.xml new file mode 100644 index 000000000..12419524d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rCA/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s and sign in. Then enter this code: + ]]> + + TRY ALEXA + Privacy Notice + Terms of Use + Try Again + SIGN IN + SIGN IN LATER + Please wait. Connecting to AACS… + Use voice to make the most of your drive. Alexa can help with directions, music, calls and much more. + Enable Alexa without sign in? + AGREE & ENABLE ALEXA + You can still talk to Alexa for things like information and getting directions. For music, weather, smart home and more, sign in. + Amazon processes and retains Alexa interactions and other data in the cloud to provide and improve our services. By selecting \“Agree & Enable Alexa\“ you accept Amazon\’s Conditions of Use and all the terms found here. \n\n Learn how Alexa is designed to protect your privacy. + There was an issue enabling Preview mode. Please try again. + Or scan this code: + You\'re all done%1$s! + Try: + NETWORK SETTINGS + Network Error + Alexa needs access to the internet to complete setup. \n Please check your network connection and try again. + Sign in to your Amazon account + \"Alexa, set the temperature to 22\" + \"Alexa, find a café\" + \"Alexa, play music\" + \"Alexa, set the temperature to 22\" + \"Alexa, take me to the airport\" + \"Alexa, tune in to 88.5 FM\" + For music, weather, smart home and more, sign in. + DONE + Alexa\'s language + SELECT LANGUAGE + Alexa isn\'t available in %1$s. Select a language for Alexa. + CONTINUE + Something\'s gone wrong + There was an issue setting up Alexa. Please try again. + There was an issue setting up. Please try again. + There was an issue signing in. Please try again. + TRY AGAIN + SKIP + USE LOCATION + What\'s nearby? + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather and more. + \"Alexa, find restaurants near me\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rIN/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rIN/strings.xml new file mode 100644 index 000000000..12419524d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rIN/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s and sign in. Then enter this code: + ]]> + + TRY ALEXA + Privacy Notice + Terms of Use + Try Again + SIGN IN + SIGN IN LATER + Please wait. Connecting to AACS… + Use voice to make the most of your drive. Alexa can help with directions, music, calls and much more. + Enable Alexa without sign in? + AGREE & ENABLE ALEXA + You can still talk to Alexa for things like information and getting directions. For music, weather, smart home and more, sign in. + Amazon processes and retains Alexa interactions and other data in the cloud to provide and improve our services. By selecting \“Agree & Enable Alexa\“ you accept Amazon\’s Conditions of Use and all the terms found here. \n\n Learn how Alexa is designed to protect your privacy. + There was an issue enabling Preview mode. Please try again. + Or scan this code: + You\'re all done%1$s! + Try: + NETWORK SETTINGS + Network Error + Alexa needs access to the internet to complete setup. \n Please check your network connection and try again. + Sign in to your Amazon account + \"Alexa, set the temperature to 22\" + \"Alexa, find a café\" + \"Alexa, play music\" + \"Alexa, set the temperature to 22\" + \"Alexa, take me to the airport\" + \"Alexa, tune in to 88.5 FM\" + For music, weather, smart home and more, sign in. + DONE + Alexa\'s language + SELECT LANGUAGE + Alexa isn\'t available in %1$s. Select a language for Alexa. + CONTINUE + Something\'s gone wrong + There was an issue setting up Alexa. Please try again. + There was an issue setting up. Please try again. + There was an issue signing in. Please try again. + TRY AGAIN + SKIP + USE LOCATION + What\'s nearby? + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather and more. + \"Alexa, find restaurants near me\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rUS/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rUS/strings.xml new file mode 100644 index 000000000..afab1e9d7 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en-rUS/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s and sign in. Then enter this code: + ]]> + + TRY ALEXA + Privacy Notice + Terms of Use + Try Again + SIGN IN + SIGN IN LATER + Please wait for connecting to AACS… + Use voice to make the most of your drive. Alexa can help with directions, music, calls, and much more. + Enable Alexa without sign in? + AGREE & ENABLE ALEXA + You can still talk to Alexa for things like info and getting directions. For music, weather, smart home and more, sign in. + Amazon processes and retains Alexa interactions and other data in the cloud to provide and improve our services. By selecting \“Agree & Enable Alexa\“ you accept Amazon\’s Conditions of Use and all the terms found here. \n\n Learn how Alexa is designed to protect your privacy. + There was an issue enabling Preview Mode. Please try again. + Or scan this code: + You\'re all set%1$s! + Try: + NETWORK SETTINGS + Network Error + Alexa needs access to the internet to complete setup. \n Please check your network connection and try again. + Sign in to your Amazon account + \"Alexa, set the temperature to 72\" + \"Alexa, find a coffee shop\" + \"Alexa, play music\" + \"Alexa, set the temperature to 72\" + \"Alexa, take me to the airport\" + \"Alexa, tune to 88.5 FM\" + For music, weather, smart home, and more, sign in. + DONE + Alexa\'s language + SELECT LANGUAGE + Alexa isn\'t available in %1$s. Select a language for Alexa. + CONTINUE + Something\'s gone wrong + There was an issue setting up Alexa. Please try again. + There was an issue setting up. Please try again. + There was an issue signing in. Please try again. + TRY AGAIN + SKIP + USE LOCATION + What\'s nearby? + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather, and more. + \"Alexa, find restaurants near me\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en/strings.xml new file mode 100644 index 000000000..12419524d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-en/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s and sign in. Then enter this code: + ]]> + + TRY ALEXA + Privacy Notice + Terms of Use + Try Again + SIGN IN + SIGN IN LATER + Please wait. Connecting to AACS… + Use voice to make the most of your drive. Alexa can help with directions, music, calls and much more. + Enable Alexa without sign in? + AGREE & ENABLE ALEXA + You can still talk to Alexa for things like information and getting directions. For music, weather, smart home and more, sign in. + Amazon processes and retains Alexa interactions and other data in the cloud to provide and improve our services. By selecting \“Agree & Enable Alexa\“ you accept Amazon\’s Conditions of Use and all the terms found here. \n\n Learn how Alexa is designed to protect your privacy. + There was an issue enabling Preview mode. Please try again. + Or scan this code: + You\'re all done%1$s! + Try: + NETWORK SETTINGS + Network Error + Alexa needs access to the internet to complete setup. \n Please check your network connection and try again. + Sign in to your Amazon account + \"Alexa, set the temperature to 22\" + \"Alexa, find a café\" + \"Alexa, play music\" + \"Alexa, set the temperature to 22\" + \"Alexa, take me to the airport\" + \"Alexa, tune in to 88.5 FM\" + For music, weather, smart home and more, sign in. + DONE + Alexa\'s language + SELECT LANGUAGE + Alexa isn\'t available in %1$s. Select a language for Alexa. + CONTINUE + Something\'s gone wrong + There was an issue setting up Alexa. Please try again. + There was an issue setting up. Please try again. + There was an issue signing in. Please try again. + TRY AGAIN + SKIP + USE LOCATION + What\'s nearby? + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather and more. + \"Alexa, find restaurants near me\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rMX/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rMX/strings.xml new file mode 100644 index 000000000..31b63da94 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rMX/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s e inicia sesión. Después, escribe este código: + ]]> + + PROBAR ALEXA + Aviso de privacidad + Términos de uso + Volver a intentar + INICIAR SESIÓN + INICIAR SESIÓN MÁS TARDE + Espera para conectarte a AACS… + Usa la voz para sacar el máximo provecho de la conducción. Alexa puede ayudarte con indicaciones, música, llamadas y mucho más. + ¿Quieres activar Alexa sin iniciar sesión? + ACEPTAR Y ACTIVAR ALEXA + Podrás seguir comunicándote con Alexa para obtener información e indicaciones sobre cómo llegar a un lugar. Inicia sesión para escuchar música, obtener el estado del tiempo, usar las opciones de Casa Inteligente y mucho más. + Amazon procesa y retiene interacciones y otros datos de Alexa en la nube para proporcionar y mejorar nuestros servicios. Al seleccionar Aceptar y activar Alexa, aceptas las condiciones de uso de Amazon y todos los términos que se encuentran aquí. \n\n Descubre cómo es que Alexa se diseñó para proteger tu privacidad. + Hubo un problema al activar el modo de vista previa. Vuelve a intentarlo. + O escanea este código: + ¡Todo listo,%1$s! + Di: + CONFIGURACIÓN DE RED + Error de red + Alexa necesita acceso a Internet para completar la configuración. \n Revisa tu conexión de red y vuelve a intentarlo. + Iniciar sesión en tu cuenta de Amazon + “Alexa, pon la temperatura a 22 grados” + “Alexa, busca una cafetería” + “Alexa, pon música” + “Alexa, pon la temperatura a 22 grados” + “Alexa, llévame al aeropuerto” + “Alexa, pon la estación de radio 88.5 FM” + Inicia sesión para escuchar música, obtener el estado del tiempo, usar las opciones de Casa Inteligente y mucho más. + LISTO + Idioma de Alexa + SELECCIONAR IDIOMA + Alexa no está disponible en %1$s. Selecciona un idioma para Alexa. + CONTINUAR + Ocurrió un error + Hubo un problema con la configuración de Alexa. Vuelve a intentarlo. + Hubo un problema con la configuración. Vuelve a intentarlo. + Hubo un problema al iniciar sesión. Vuelve a intentarlo. + VOLVER A INTENTAR + OMITIR + USAR UBICACIÓN + ¿Qué hay cerca? + Comparte la ubicación actual de tu vehículo con Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + Comparte la ubicación actual de tu vehículo con [Brandon] y Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + “Alexa, busca restaurantes cerca de mí” + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rUS/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rUS/strings.xml new file mode 100644 index 000000000..d52ef0a9a --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es-rUS/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s e inicia sesión. Después, escribe este código: + ]]> + + PROBAR ALEXA + Aviso de privacidad + Términos de uso + Volver a intentar + INICIAR SESIÓN + INICIAR SESIÓN MÁS TARDE + Espera para conectarte a AACS… + Usa la voz para sacar el máximo provecho de la conducción. Alexa puede ayudarte con indicaciones, música, llamadas y mucho más. + ¿Quieres activar Alexa sin iniciar sesión? + ACEPTAR Y ACTIVAR ALEXA + Podrás seguir comunicándote con Alexa para obtener información e indicaciones sobre cómo llegar a un lugar. Inicia sesión para escuchar música, obtener el estado del tiempo, usar las opciones de Smart Home y mucho más. + Amazon procesa y retiene interacciones y otros datos de Alexa en la nube para proporcionar y mejorar nuestros servicios. Al seleccionar Aceptar y activar Alexa, aceptas las condiciones de uso de Amazon y todos los términos que se encuentran aquí. \n\n Descubre cómo es que Alexa se diseñó para proteger tu privacidad. + Hubo un problema al activar el modo de vista previa. Vuelve a intentarlo. + O escanea este código: + ¡Todo listo,%1$s! + Di: + CONFIGURACIÓN DE RED + Error de red + Alexa necesita acceso a Internet para completar la configuración. \n Revisa tu conexión de red y vuelve a intentarlo. + Iniciar sesión en tu cuenta de Amazon + “Alexa, pon la temperatura a 72 grados” + “Alexa, busca una cafetería” + “Alexa, pon música” + “Alexa, pon la temperatura a 72 grados” + “Alexa, llévame al aeropuerto” + “Alexa, pon la estación de radio 88.5 FM” + Inicia sesión para escuchar música, obtener el estado del tiempo, usar las opciones de Smart Home y mucho más. + LISTO + Idioma de Alexa + SELECCIONAR IDIOMA + Alexa no está disponible en %1$s. Selecciona un idioma para Alexa. + CONTINUAR + Ocurrió un error + Hubo un problema con la configuración de Alexa. Vuelve a intentarlo. + Hubo un problema con la configuración. Vuelve a intentarlo. + Hubo un problema al iniciar sesión. Vuelve a intentarlo. + VOLVER A INTENTAR + OMITIR + USAR UBICACIÓN + ¿Qué hay cerca? + Comparte la ubicación actual de tu vehículo con Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + Comparte la ubicación actual de tu vehículo con [Brandon] y Alexa para obtener respuestas más específicas sobre restaurantes cercanos, el clima local y más. + “Alexa, busca restaurantes cerca de mí” + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es/strings.xml new file mode 100644 index 000000000..9f5d999e9 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-es/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s e inicia sesión. Luego introduce este código: + ]]> + + PROBAR ALEXA + Aviso de privacidad + Términos de uso + Volver a intentarlo + INICIAR SESIÓN + INICIAR SESIÓN MÁS TARDE + Espera un momento mientras conectamos con AACS… + Usa la voz para sacar el máximo partido a tu trayecto. Alexa puede ayudarte con indicaciones, música, llamadas y mucho más. + ¿Activar Alexa sin iniciar sesión? + ACEPTAR Y ACTIVAR ALEXA + Podrás pedirle a Alexa información e indicaciones. Para usar las funcionalidades de música, información digital y Hogar digital, entre otras, inicia sesión. + Amazon procesa y guarda en el Cloud de Amazon las interacciones con Alexa, así como otros datos, para proporcionar y mejorar nuestros servicios. Al seleccionar Aceptar y activar Alexa, aceptas las Condiciones de uso de Amazon y los términos descritos aquí. \n\n Descubre cómo Alexa está diseñada para proteger tu privacidad. + Se ha producido un problema al activar el modo de vista previa. Vuelve a intentarlo. + O escanea este código: + ¡Todo listo%1$s! + Di: + CONFIGURACIÓN DE RED + Error de red + Alexa necesita acceso a Internet para completar la configuración. \n Comprueba la conexión de red y vuelve a intentarlo. + Iniciar sesión con tu cuenta Amazon + \"Alexa, pon la temperatura a 22 grados\" + \"Alexa, busca una cafetería\" + \"Alexa, pon la música\" + \"Alexa, pon la temperatura a 22 grados\" + \"Alexa, guíame hasta el aeropuerto\" + \"Alexa, pon la 88.5 FM\" + Inicia sesión para usar las funcionalidades de música, información del tiempo, Hogar digital y mucho más. + LISTO + Idioma de Alexa + SELECCIONAR IDIOMA + Alexa no está disponible en %1$s. Selecciona un idioma para Alexa. + CONTINUAR + Se ha producido un error + Se ha producido un problema al configurar Alexa. Vuelve a intentarlo. + Se ha producido un problema en la configuración. Vuelve a intentarlo. + Se ha producido un problema al iniciar sesión. Vuelve a intentarlo. + VOLVER A INTENTARLO + OMITIR + USAR UBICACIÓN + ¿Qué hay cerca de aquí? + Comparte la ubicación actual de tu vehículo con Alexa para recibir respuestas más precisas respecto a restaurantes cercanos, el tiempo local y más. + Comparte la ubicación actual de tu vehículo con [Brandon] y Alexa para recibir respuestas más precisas respecto a restaurantes cercanos, el tiempo local y más. + \"Alexa, busca restaurantes cerca de aquí\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr-rCA/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr-rCA/strings.xml new file mode 100644 index 000000000..43d2347da --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr-rCA/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s et connectez-vous. Puis saisissez ce code : + ]]> + + ESSAYER ALEXA + Avis de confidentialité + Conditions d\'utilisation + Réessayer + SE CONNECTER + SE CONNECTER PLUS TARD + Veuillez patienter pendant la connexion à AACS… + Utilisez la voix pour tirer le maximum de votre conduite. Alexa peut vous aider avec les itinéraires, la musique, les appels, et plus encore. + Activer Alexa sans se connecter? + ACCEPTER ET ACTIVER ALEXA + Vous pouvez continuer à parler à Alexa pour demander les nouvelles et obtenir des itinéraires. Pour la musique, la météo, la maison intelligente et plus encore, connectez-vous. + Amazon traite et retient les interactions d\'Alexa et des autres données dans le nuage pour fournir et améliorer nos services. En sélectionnant « Accepter et activer Alexa », vous acceptez les Conditions d\'utilisation Amazon et toutes les conditions disponibles ici. \n\nDécouvrez comment Alexa est conçue pour protéger votre vie privée. + Un problème est survenu pendant l\'activation du mode Aperçu. Veuillez réessayer. + Ou scannez ce code : + Tout est prêt, %1$s! + Essayez : + PARAMÈTRES RÉSEAU + Erreur réseau + Alexa a besoin d\'accéder à l\'Internet pour terminer la configuration. \n Veuillez vérifier votre connexion réseau et réessayer. + Connectez-vous à votre compte Amazon + « Alexa, règle la température sur 22. » + « Alexa, trouve un café » + « Alexa, joue de la musique » + « Alexa, règle la température sur 22. » + « Alexa, emmène-moi à l\'aéroport. » + « Alexa, règle la radio sur 88,5 FM. » + Pour la musique, la météo, la maison intelligente, et plus encore, connectez-vous. + TERMINÉ + Langue d\'Alexa + SÉLECTIONNER LA LANGUE + Alexa n\'est pas disponible en %1$s. Sélectionnez une langue pour Alexa. + CONTINUER + Un problème est survenu + Un problème est survenu pendant la configuration d\'Alexa. Veuillez réessayer. + Un problème est survenu pendant la configuration. Veuillez réessayer. + Un problème est survenu pendant la connexion. Veuillez réessayer. + RÉESSAYER + IGNORER + UTILISER LA LOCALISATION + Qu\'y a-t-il à proximité? + Partagez la localisation de votre véhicule avec Alexa pour obtenir des réponses plus intelligentes sur les restaurants à proximité, la météo locale et plus encore. + Partagez la localisation de votre véhicule avec [Brandon] et Alexa pour obtenir des réponses plus intelligentes sur les restaurants à proximité, la météo locale et plus encore. + « Alexa, trouve des restaurants à proximité. » + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr/strings.xml new file mode 100644 index 000000000..e7323bdee --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-fr/strings.xml @@ -0,0 +1,52 @@ + + + + %1$s et connectez-vous. Saisissez ensuite ce code : + ]]> + + ESSAYER ALEXA + Notice Protection de vos informations personnelles + Conditions d\'utilisation + Réessayer + SE CONNECTER + SE CONNECTER PLUS TARD + Veuillez patienter pendant la connexion à AACS… + Utilisez votre voix pour profiter au mieux de votre trajet. Alexa peut vous aider avec l\'itinéraire, la musique, les appels et bien plus. + Activer Alexa sans se connecter ? + ACCEPTER ET ACTIVER ALEXA + Vous pouvez toujours parler à Alexa pour demander des informations ou obtenir un itinéraire. Pour de la musique, la météo, la maison connectée et plus encore, connectez-vous. + Amazon traite et conserve les interactions et autres données Alexa dans le Cloud Amazon. En sélectionnant Accepter et activer Alexa, vous acceptez les Conditions d\'utilisation Amazon et toutes les conditions que vous trouverez ici. \n\nEn savoir plus sur la manière dont Alexa est conçue pour protéger votre vie privée + + Un problème est survenu lors de l\'activation du mode aperçu. Veuillez réessayer. + Ou scannez ce code : + Vous avez terminé %1$s ! + Essayez : + PARAMÈTRES RÉSEAU + Erreur réseau + Alexa doit accéder à Internet pour terminer la configuration. \n Veuillez vérifier votre connexion réseau, puis réessayer. + Connexion à votre compte Amazon + « Alexa, règle la température sur 22 degrés. » + « Alexa, trouve un café. » + « Alexa, joue de la musique. » + « Alexa, règle la température sur 22 degrés. » + « Alexa, emmène-moi à l\'aéroport. » + « Alexa, mets 88.5 FM. » + Connectez-vous pour écouter de la musique, obtenir la météo, contrôler des appareils connectés et bien plus. + TERMINÉ + Langue d\'Alexa + SÉLECTIONNER LA LANGUE + Alexa n\'est pas disponible en %1$s. Sélectionnez une langue pour Alexa. + CONTINUER + Un problème est survenu + Un problème est survenu lors de la configuration d\'Alexa. Veuillez réessayer. + Un problème est survenu lors de la configuration. Veuillez réessayer. + Un problème est survenu lors de la connexion. Veuillez réessayer. + RÉESSAYER + IGNORER + UTILISER LA LOCALISATION + Qu\'est-ce qu\'il y a à proximité ? + Partagez la localisation actuelle de votre véhicule avec Alexa pour obtenir des réponses plus pertinentes concernant les restaurants à proximité, la météo locale et bien plus encore. + Partagez la localisation actuelle de votre véhicule avec [Brandon] et Alexa pour obtenir des réponses plus pertinentes concernant les restaurants à proximité, la météo locale et bien plus encore. + « Alexa, trouve des restaurants à proximité. » + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-hi-rIN/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-hi-rIN/strings.xml new file mode 100644 index 000000000..33ddd292e --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-hi-rIN/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s पर जाएं और साइन इन करें. इसके बाद, + ]]> +कोड डालें + ALEXA को आज़माकर देखें + प्राइवेसी नोटिस + इस्तेमाल की शर्तें + फिर से कोशिश करें + साइन इन करें + बाद में साइन इन करें + कृपया इंतज़ार करें, AACS से कनेक्ट किया जा रहा है… + गाड़ी चलाते समय बस बोलकर कई सुविधाएं इस्तेमाल करें. Alexa से आपको रास्ते की जानकारी, म्यूज़िक, कॉल, और कई दूसरी चीज़ों में मदद मिल सकती है. + बिना साइन इन किए Alexa को चालू करना है? + सहमति दें और ALEXA को चालू करें + आपके पास अब भी जानकारी और रास्तों के बारे में पता करने जैसी चीज़ों के लिए, Alexa से बात करने की सुविधा है. म्यूज़िक, मौसम, स्मार्ट होम, और कई दूसरी चीज़ों के लिए, साइन इन करें. + Amazon, Alexa से होने वाली बातचीत और अन्य डेटा को Amazon क्लाउड में प्रोसेस करता है और सेव करके रखता है. \"सहमति दें और चालू करें\" को चुनने का मतलब है कि आप Amazon की इस्तेमाल की शर्तों और यहां दी गई सभी शर्तों से सहमत हैं. \n\n जानें कि कैसे Alexa को आपकी प्राइवेसी की सुरक्षा के लिए डिज़ाइन किया गया है. + प्रीव्यू मोड मोड को चालू करते समय कोई गड़बड़ी हुई. कृपया फिर से कोशिश करें. + या यहां दिए गए कोड को स्कैन करें: + आप पूरी तरह तैयार हैं%1$s! + कोशिश करें: + नेटवर्क की सेटिंग + नेटवर्क की गड़बड़ी + Alexa को सेटअप पूरा करने के लिए इंटरनेट की ज़रूरत है. \n कृपया अपने नेटवर्क कनेक्शन की जांच करें और फिर से कोशिश करें. + अपने Amazon अकाउंट में साइन इन करें + \"Alexa, तापमान को 22 पर सेट करो\" + \"Alexa, कॉफ़ी शॉप ढूंढो\" + \"Alexa, म्यूज़िक चलाओ\" + \"Alexa, तापमान को 22 पर सेट करो\" + \"Alexa, मुझे एयरपोर्ट ले चलो\" + \"Alexa, 88.5 FM पर ट्यून करो\" + म्यूज़िक, मौसम, स्मार्ट होम, और कई दूसरी चीज़ों के लिए, साइन इन करें. + हो गया + Alexa की भाषा + भाषा चुनें + Alexa %1$s में उपलब्ध नहीं है. Alexa के लिए भाषा चुनें. + जारी रखें + कुछ समस्या हुई है + Alexa को सेट अप करते समय कोई गड़बड़ी हुई. कृपया फिर से कोशिश करें. + सेट अप करते समय कोई गड़बड़ी हुई. कृपया फिर से कोशिश करें. + साइन इन करते समय कोई गड़बड़ी हुई. कृपया फिर से कोशिश करें. + फिर से कोशिश करें + छोड़ें + लोकेशन इस्तेमाल करें + आस-पास में क्या है? + आस-पास के रेस्टोरेंट, स्थानीय मौसम और कई दूसरी चीज़ों के बारे में बेहतर जवाब पाने के लिए, अपनी गाड़ी की मौजूदा लोकेशन को Alexa के साथ शेयर करें. + आस-पास के रेस्टोरेंट, स्थानीय मौसम और बहुत सी चीज़ों पर बेहतर जवाब पाने के लिए अपनी गाड़ी की मौजूदा लोकेशन को [Brandon] और Alexa के साथ शेयर करें. + \"Alexa, मेरे आस-पास के रेस्टोरेंट ढूंढो\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-it/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-it/strings.xml new file mode 100644 index 000000000..5089ec5bf --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-it/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s ed effettua l\'accesso. Poi inserisci questo codice: + ]]> + + PROVA ALEXA + Informativa sulla privacy + Termini di utilizzo + Riprova + ACCEDI + ACCEDI PIÙ TARDI + Ti preghiamo di attendere per connetterti ad AACS… + Usa la voce per sfruttare al meglio il tempo che passi in auto. Alexa può aiutarti con indicazioni stradali, musica, chiamate e molto altro ancora. + Attivare Alexa senza accedere? + ACCETTA E ATTIVA ALEXA + Puoi ancora parlare con Alexa per ricevere informazioni e indicazioni stradali. Per musica, meteo, Casa Intelligente e altro ancora, effettua l\'accesso. + Amazon elabora e conserva le interazioni e altri dati di Alexa nel Cloud, per fornire e migliorare i servizi. Selezionando \"Accetta e attiva Alexa\", accetti le Condizioni d\'uso di Amazon e tutti i termini riportati qui. \n\n Scopri come Alexa è progettata per proteggere la tua privacy. + Si è verificato un errore nell\'attivazione della modalità Anteprima. Riprova. + Oppure scansiona questo codice: + È tutto pronto%1$s! + Prova: + IMPOSTAZIONI DI RETE + Errore di rete + Alexa ha bisogno di accedere a Internet per completare la configurazione. \n Verifica la tua connessione di rete e riprova. + Accedi al tuo account Amazon + \"Alexa, imposta la temperatura su 22 gradi\" + \"Alexa, cerca una caffetteria\" + \"Alexa, metti della musica\" + \"Alexa, imposta la temperatura su 22 gradi\" + \"Alexa, portami in aeroporto\" + \"Alexa, sintonizzati su 88,5 FM\" + Per musica, meteo, Casa Intelligente e altro ancora, effettua l\'accesso. + FATTO + La lingua di Alexa + SELEZIONA LA LINGUA + Alexa non è disponibile in %1$s. Scegli una lingua per Alexa. + CONTINUA + Si è verificato un problema + Si è verificato un errore nella configurazione di Alexa. Riprova. + Si è verificato un errore nella configurazione. Riprova. + Si è verificato un problema in fase di accesso. Riprova. + RIPROVA + SALTA + USA POSIZIONE + Cosa c\'è nelle vicinanze? + Condividi la posizione attuale del tuo veicolo con Alexa per ottenere risposte più pertinenti su ristoranti nelle vicinanze, il meteo locale e molto altro. + Condividi la posizione attuale del tuo veicolo con [Brandon] e Alexa per ottenere risposte più pertinenti su ristoranti nelle vicinanze, il meteo locale e molto altro. + \"Alexa, cerca un ristorante nelle vicinanze\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-ja/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-ja/strings.xml new file mode 100644 index 000000000..0a2829360 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-ja/strings.xml @@ -0,0 +1,51 @@ + + + + %1$sでサインインしてください。 + ]]> + + Alexaを試す + プライバシー規約 + 利用規約 + もう一度試す + サインイン + 後でサインイン + AACSに接続中です。お待ちください… + 音声操作で快適にドライブ。Alexaに話しかけるだけで道案内、音楽再生、通話などを開始できます。 + Alexaにサインインせずにオンにしますか? + 同意してAlexaをオンにする + サインインしなくても、Alexaに情報や道順などを尋ねることはできます。音楽再生、天気予報、スマートホームの操作などにはサインインが必要です。 + Amazonは、サービスの提供と改善のため、Amazon Alexaとの会話やその他のデータをAmazonのクラウドで処理および保存します。お客様は、「同意してAlexaをオンにする」を選択することでAmazonの利用規約ここに記載されているすべての規約に同意したものとみなされます。\n\nAlexaが、お客様のプライバシーを重視するためにどのように設計されているかの詳細については、こちらをご覧ください + プレビューモードをオンにできませんでした。もう一度試してください。 + または、このコードをスキャンしてください。 + セットアップが完了しました%1$s! + 次のように言ってみてください。 + ネットワークの設定 + ネットワークエラー + Alexaのセットアップを完了するには、インターネットへの接続が必要です。\nネットワークの接続を確認してもう一度試してください。 + Amazonアカウントにサインイン + 「アレクサ、温度を22度に設定して」 + 「アレクサ、カフェを探して」 + 「アレクサ、音楽をかけて」 + 「アレクサ、温度を22度に設定して」 + 「アレクサ、空港まで連れて行って」 + 「アレクサ、92.3 FMをつけて」 + サインインして、音楽再生、天気予報、スマートホームの操作などをお試しください。 + 完了 + Alexaの言語 + 言語を選択 + Alexaは%1$sで利用できません。他の言語を選択してください。 + 次へ + うまくいきませんでした + Alexaをセットアップできませんでした。もう一度試してください。 + セットアップできませんでした。もう一度試してください。 + サインインできませんでした。もう一度試してください。 + もう一度試す + スキップ + 位置情報を使用 + ローカル検索 + 車の位置情報へのアクセスをAlexaに許可すると、最寄りのレストランや地域の天気予報など、状況に合った情報を得ることができます。 + 車の位置情報へのアクセスを[Brandon]とAlexaに許可すると、最寄りのレストランや地域の天気予報など、状況に合った情報を得ることができます。 + 「アレクサ、近くのレストランを検索して」 + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-land/dimens.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-land/dimens.xml new file mode 100644 index 000000000..0c62a0c3d --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-land/dimens.xml @@ -0,0 +1,28 @@ + + + + 150dp + 108dp + 200dp + 130dp + 8dp + 50dp + 8dp + 100dp + 100dp + 20sp + 120dp + + 16dp + 50dp + 50dp + 32dp + + 180dp + + 185dp + 150dp + + 5dp + 35dp + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values-pt-rBR/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-pt-rBR/strings.xml new file mode 100644 index 000000000..eb79f8356 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values-pt-rBR/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s e inicie a sessão. Em seguida, insira este código: + ]]> + + EXPERIMENTAR A ALEXA + Aviso de Privacidade + Termos de uso + Tente novamente + INICIAR SESSÃO + INICIAR SESSÃO MAIS TARDE + Aguarde a conexão com AACS… + Use a voz para aproveitar ao máximo sua experiência ao volante. A Alexa pode ajudar com rotas, música, chamadas e muito mais. + Ativar a Alexa sem iniciar sessão? + CONCORDAR E ATIVAR A ALEXA + Você ainda pode falar com a Alexa para obter informações e rotas, entre outras coisas. Para música, previsão do tempo, recursos de casa inteligente e muito mais, inicie a sessão. + A Amazon processa e mantém as interações da Alexa e outros dados na nuvem para fornecer e aprimorar nossos serviços. Ao selecionar \"Concordar e ativar a Alexa\", você aceita as Condições de Uso da Amazon e todos os termos disponíveis aqui. \n\n Saiba como a Alexa foi projetada para proteger sua privacidade. + Ocorreu um problema ao ativar o modo de visualização. Tente novamente. + Ou digitalize este código: + Está tudo pronto%1$s! + Tente: + CONFIGURAÇÕES DE REDE + Erro de rede + A Alexa precisa acessar a Internet para concluir a configuração. \n Verifique sua conexão de rede e tente novamente. + Iniciar sessão na sua conta da Amazon + \"Alexa, ajuste a temperatura para 22\" + “Alexa, encontre uma cafeteria” + “Alexa, toque músicas” + \"Alexa, ajuste a temperatura para 22\" + \"Alexa, me leve para o aeroporto\" + \"Alexa, sintonize na 88.5 FM\" + Para música, previsão do tempo, recursos de casa inteligente e muito mais, inicie a sessão. + OK + Idioma da Alexa + SELECIONAR IDIOMA + A Alexa não está disponível em %1$s. Selecione um idioma para a Alexa. + CONTINUAR + Ocorreu um problema + Ocorreu um problema ao configurar a Alexa . Tente novamente. + Ocorreu um problema de configuração. Tente novamente. + Ocorreu um problema ao iniciar a sessão. Tente novamente. + TENTE NOVAMENTE + PULAR + USAR LOCALIZAÇÃO + O que tem nas proximidades? + Compartilhe a localização atual do seu veículo com a Alexa para obter respostas mais inteligentes para restaurantes nas proximidades, previsão do tempo local e muito mais. + Compartilhe a localização atual do seu veículo com o [Brandon] e a Alexa para obter respostas mais inteligentes para restaurantes nas proximidades, previsão do tempo local e muito mais. + \"Alexa, encontre restaurante por perto\" + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values/dimens.xml new file mode 100644 index 000000000..5ae5cfc3b --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values/dimens.xml @@ -0,0 +1,34 @@ + + + + 150dp + 108dp + 200dp + 130dp + 32dp + 100dp + 32dp + 60dp + 50dp + 280dp + 8dp + 32dp + 100dp + 500dp + 100dp + 20sp + 150dp + + 8dp + 50dp + 50dp + 32dp + + 340dp + + 145dp + 110dp + + 2dp + 50dp + diff --git a/aacs/android/app-components/alexa-auto-setup/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-setup/src/main/res/values/strings.xml new file mode 100644 index 000000000..ef4b90ba1 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-setup/src/main/res/values/strings.xml @@ -0,0 +1,51 @@ + + + + %1$s and sign in. Then enter this code: + ]]> + + TRY ALEXA + Privacy Notice + Terms of Use + Try Again + SIGN IN + SIGN IN LATER + Please wait for connecting to AACS… + Use voice to make the most of your drive. Alexa can help with directions, music, calls, and much more. + Enable Alexa without sign in? + AGREE & ENABLE ALEXA + You can still talk to Alexa for things like info and getting directions. For music, weather, smart home and more, sign in. + Amazon processes and retains Alexa interactions and other data in the cloud to provide and improve our services. By selecting \“Agree & Enable Alexa\“ you accept Amazon\’s Conditions of Use and all the terms found here. \n\n Learn how Alexa is designed to protect your privacy. + There was an issue enabling Preview Mode. Please try again. + Or scan this code: + You\'re all set%1$s! + Try: + NETWORK SETTINGS + Network Error + Alexa needs access to the internet to complete setup. \n Please check your network connection and try again. + Sign in to your Amazon account + \"Alexa, set the temperature to 72\" + \"Alexa, find a coffee shop\" + \"Alexa, play music\" + \"Alexa, set the temperature to 72\" + \"Alexa, take me to the airport\" + \"Alexa, tune to 88.5 FM\" + For music, weather, smart home, and more, sign in. + DONE + Alexa\'s language + SELECT LANGUAGE + Alexa isn\'t available in %1$s. Select a language for Alexa. + CONTINUE + Something\'s gone wrong + There was an issue setting up Alexa. Please try again. + There was an issue setting up. Please try again. + There was an issue signing in. Please try again. + TRY AGAIN + SKIP + USE LOCATION + What\'s nearby? + Share your vehicle\'s current location with Alexa to get smarter responses for nearby restaurants, local weather and more. + Share your vehicle\'s current location with [Brandon] and Alexa to get smarter responses for nearby restaurants, local weather, and more. + \"Alexa, find restaurants near me\" + diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/TestResourceFileReader.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/TestResourceFileReader.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/TestResourceFileReader.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/TestResourceFileReader.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigatorTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigatorTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigatorTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowNavigatorTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowProviderTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowProviderTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowProviderTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/WorkflowProviderTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommandTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommandTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommandTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/CheckLocationConsentCommandTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommandTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommandTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommandTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/command/SetupCompleteCommandTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/AuthProviderAuthenticatedFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginErrorFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLLoginFinishFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java similarity index 85% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java index 08046e340..7f156235e 100644 --- a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java +++ b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/CBLViewModelTest.java @@ -1,5 +1,8 @@ package com.amazon.alexa.auto.setup.workflow.fragment; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.EARCON_SETTINGS; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.EARCON_SETTINGS_END; +import static com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider.EARCON_SETTINGS_START; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.times; @@ -8,6 +11,7 @@ import android.app.Application; import android.content.Context; +import android.content.SharedPreferences; import androidx.arch.core.executor.testing.InstantTaskExecutorRule; @@ -48,6 +52,10 @@ public class CBLViewModelTest { @Mock AlexaAppRootComponent mMockRootComponent; @Mock + SharedPreferences mMockSharedPrefs; + @Mock + SharedPreferences.Editor mMockEditor; + @Mock AuthController mMockAuthController; @Mock LoginUIEventListener mMockLoginHostBinding; @@ -69,6 +77,8 @@ public void setup() { when(mMockRootComponent.getComponent(LoginUIEventListener.class)) .thenReturn(Optional.of(mMockLoginHostBinding)); when(mMockAuthController.newAuthenticationWorkflow()).thenReturn(mAuthWorkflowSubject); + when(mMockContext.getSharedPreferences(EARCON_SETTINGS, 0)).thenReturn(mMockSharedPrefs); + when(mMockSharedPrefs.edit()).thenReturn(mMockEditor); mClassUnderTest = new CBLViewModel(mMockApplication); } @@ -79,6 +89,8 @@ public void testStartLoginStartsNewAuthWorkflow() { mClassUnderTest.startLogin(); verify(mMockAuthController, times(1)).newAuthenticationWorkflow(); + verify(mMockEditor, times(1)).putBoolean(EARCON_SETTINGS_START, true); + verify(mMockEditor, times(1)).putBoolean(EARCON_SETTINGS_END, true); } @Test diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/EnablePreviewModeFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LanguageSelectionFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LocationConsentFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModelTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModelTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModelTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/LoginViewModelTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/NetworkFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragmentTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragmentTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragmentTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/fragment/SetupNotCompleteFragmentTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/receiver/NetworkStateChangeReceiverTest.java b/aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/receiver/NetworkStateChangeReceiverTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/receiver/NetworkStateChangeReceiverTest.java rename to aacs/android/app-components/alexa-auto-setup/src/test/java/com/amazon/alexa/auto/setup/workflow/receiver/NetworkStateChangeReceiverTest.java diff --git a/platforms/android/app-components/alexa-auto-setup/src/test/resources/workflowSpecification/CBLLoginWorkflowSpecification.json b/aacs/android/app-components/alexa-auto-setup/src/test/resources/workflowSpecification/CBLLoginWorkflowSpecification.json similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/src/test/resources/workflowSpecification/CBLLoginWorkflowSpecification.json rename to aacs/android/app-components/alexa-auto-setup/src/test/resources/workflowSpecification/CBLLoginWorkflowSpecification.json diff --git a/platforms/android/app-components/alexa-auto-telephony/.gitignore b/aacs/android/app-components/alexa-auto-telephony/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/.gitignore rename to aacs/android/app-components/alexa-auto-telephony/.gitignore diff --git a/aacs/android/app-components/alexa-auto-telephony/README.md b/aacs/android/app-components/alexa-auto-telephony/README.md new file mode 100644 index 000000000..69ac5a880 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-telephony/README.md @@ -0,0 +1,212 @@ +# AACS Telephony + +The AACS Telephony library is an Android library for you to pre-integrate Alexa Phone Call Controller functionalities with Android Telephony. The library handles phone-related directives and events from and to the Alexa Auto SDK Engine, via the AACS Core Service. The library also works with the Dialer app on the car head unit. By including this optional library in AACS or your own application, you can easily integrate phone capabilities (e.g., dialing, redialing, and answering calls) with Alexa. + + +## Table of Contents +- [Overview](#overview) +- [Prerequisites](#prerequisites) +- [Building the Library](#building-the-library) +- [Setup for AACS Telephony Library](#setup-for-aacs-telephony-library) +- [Sequence Diagram](#sequence-diagram) +- [Phone Call Controlling](#phone-call-controlling) + - [Answer](#answer) + - [Dial](#dial) + - [Redial](#redial) + - [SendDTMF](#senddtmf) + - [Stop](#stop) + - [Update Device Configuration](#update-device-configuration) +- [(Optional) Receiving Device Connection Changes](#optional-receiving-device-connection-changes) +- [Known Issue](#known-issue) + +## Overview + +AACS Telephony Library is responsible for communicating with the AACS Core Service and initiating the corresponding actions based on the incoming directives from the Engine. The following list describes its major components that carry out these responsibilities: + +* The AACS Telephony Service is responsible for: + * Receiving and processing `PhoneCallController` AASB message intents from the AACS Core Service. + * Receiving defined intents from your application for specific actions, such as providing the proper Phone Account Handler to be used to place a call. + +* The AACS Telephony platform implementation (`PhoneCallController`) with the Android telephony framework is responsible for: + * Fulfilling the phone-call-related directives, which are received as intents by the AACS Telephony Service + * Capturing and reporting call state changes to the AACS Core Service + * Capturing and reporting Bluetooth connection state changes to the AACS Core Service, and broadcasting the changes to any client listeners + +The AACS Telephony Library is an optional module, which you can use as is or as a reference when you integrate the Phone Call Controller module with AACS. You can enable it in the AACS Sample App or in your application APK. + +## Prerequisites +* Your Android system needs to support the Android Telephony framework. +* Your Android system needs to have a default dialer app that provides dialer and in-call UI. +* Your Android system needs to support Bluetooth Hands-Free Profile (HFP) and Phone Book Access Profile (PBAP). Specifically, Bluetooth profiles with ID `HEADSET_CLIENT` and `PBAP_CLIENT` are required. For example, a device running Android Automotive OS supports these profiles. + +## Building the Library +You can build the library locally using the following steps: + 1) Enter the following command to change the directory: +~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app +~~~ + + 2) Enter the following command to build the Telephony library: +~~~ + ./gradlew :alexa-auto-telephony:assembleRelease +~~~ + +Replace `assembleRelease` with `assembleDebug` if you want to build the debug version of the library. The generated AAR is available at `alexa-auto-sdk/aacs/android/app-components/alexa-auto-telephony/aacstelephony/build/outputs/aar`. +You must include the `AACSIPC`, `AACSConstants`, `AACSCommonUtils`, `AACS` and `Auto SDK` AARs in your application to use with the AACS Telephony AAR. + + +To enable telephony support in the AACS Sample App, follow these steps: +1) Enter the following command to change the directory: +~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app +~~~ +2) Enter the following command to start the local build with telephony enabled. +~~~ + ./gradlew assembleLocalRelease -PenabledTelephony +~~~ +For more build options, see the [AACS Sample App README](../../sample-app/README.md#optional-arguments). + +## Setup for AACS Telephony Library +Before using the AACS Telephony Library, follow these major steps: + +1) Make the application containing the library into a system-privileged application. +2) Provide the library with appropriate system permissions. +3) Provide permission in your application's Android manifest so that the AACS Telephony Service can be started by your application. +4) Specify targets for intents from the AACS Core Service. + +### Making Application into a System-Privileged App + +The AACS Telephony Library needs to control the phone calls, and monitor the Bluetooth connection states and phone call states. Therefore, the application containing the library must be a system-privileged application. + +If the library is included in AACS, as recommended, you must run AACS as a system-privileged application. Similarly, if you put the library in your application, your application must be system-privileged. An application acquires system privilege when you install it in `/system/priv-app/`. + +### Providing System Permissions + +The AACS Telephony Library requires three system-level permissions: + +``` +android.permission.CONTROL_INCALL_EXPERIENCE +android.permission.INTERACT_ACROSS_USERS +android.permission.CAPTURE_AUDIO_OUTPUT +``` + +Grant the permissions to the package containing the AACS Telephony Library. For instructions about granting permissions, see the [Android documentation](https://source.android.com/devices/tech/config/perms-allowlist). To grant permissions to AACS, if it contains the library, use `com.amazon.alexaautoclientservice` as the package name in the XML file referenced in the Android documentation. + +### Providing Permission in Android Manifest + +For security reasons, for your application to send intents to or receive intents from the AACS Telephony Service, specify the `com.amazon.aacstelephony` permission in your application's Android manifest as follows: + +``` + +``` + +### Intent Targets + +The AACS Telephony Service listens to intents from the AACS Core Service with these topics: `AASB` and `PhoneCallController`. To specify AACS Telephony Service as the intent target, follow one of these steps: + +* Manually specify the messages in the AACS configuration file. The targets in the AACS configuration file override the ones specified by intent filters. The following example shows how to specify AACS Telephony Service as an intent target for both the `AASB` and `PhoneCallController` topics. In this example, the AACS Telephony Library AAR is part of the AACS sample app APK. For more information about specifying intent targets, see the [AACS README](../../README.md#specifying-the-intent-targets-for-handling-messages). + +``` + "AASB" : { + "type": ["","SERVICE", ...], + "package": ["", "com.amazon.alexa.auto.app", ...], + "class": ["", "com.amazon.aacstelephony.AACSTelephonyService", ...] + }, + //... other modules + "PhoneCallController" : { + "type": ["", "SERVICE", ...], + "package": ["", "com.amazon.alexa.auto.app", ...], + "class": ["", "com.amazon.aacstelephony.AACSTelephonyService", ...] + } + //... other modules +``` + +* Omit ANY targets for the `AASB` and `PhoneCallController` topics in the AACS configuration file. As a result, the intent filter defined in the AACS Telephony Library takes effect, enabling the AACS Telephony Service to receive the intents. + +## Sequence Diagram +The following sequence diagram illustrates the flow when the driver initiates a call with Alexa if the AACS Telephony Library is used. + +

+ +

+ +## Phone Call Controlling + +This section describes the phone call controlling actions and work flows, whether the calls are initiated by Alexa or by the user from the head unit or mobile phone. + +### Answer + +When a user asks Alexa to answer a call, the AACS Telephony Library answers the call that has the matching `callId` in the `PhoneCallController.Answer` payload of the AASB message. + +### Dial + +When a user asks Alexa to dial a number or call an uploaded contact, the AACS Telephony Service calls the Android API [getDefaultOutgoingPhoneAccount](https://developer.android.com/reference/android/telecom/TelecomManager#getDefaultOutgoingPhoneAccount(java.lang.String)) to determine the proper [PhoneAccountHandle](https://developer.android.com/reference/android/telecom/PhoneAccountHandle) to use for initiating the call. + +The specific account returned by `getDefaultOutgoingPhoneAccount` depends on the following priorities: +* If the user-selected default PhoneAccount supports the specified scheme, it will be returned. +* If there exists only one PhoneAccount that supports the specified scheme, it will be returned. + +In the Android Automotive OS the last connected device with HFP enabled is considered as the user-selected phone account. The OEMs can override this default behavior by implementing their own phone selection UI and calling the system API `setUserSelectedOutgoingPhoneAccount` to set the user selected account whenever the user makes a selection. + +>**Note:** The AACS Telephony Service does not cache the phone account handle. Each time it receives the `Dial` message from AACS, it calls the `getDefaultOutgoingPhoneAccount` to determine which phone account handle to use. + +### Redial + +Similar to the Dial action, each Redial action requires the AACS Telephony Service to call the `getDefaultOutgoingPhoneAccount` to get the proper phone account handle. The AACS Telephony phone call controller queries the Android system on the head unit by using the `CallLog.Calls.getLastOutgoingCall` method, to get the last dialed number. + +### SendDTMF + +When AACS Telephony Service gets a `sendDTMF` message, it applies the specified Dual Tone Multiple-Frequency (DTMF) tones to the call that has the matching `callId` in the `PhoneCallController.SendDTMF` payload of the AASB message. + +### Stop + +When AACS Telephony Service gets a `PhoneCallController.Stop` AASB message, it stops the current call that has the matching `callId` in the message payload. + +### Update Device Configuration + +This section describes how to update the device configuration. + +>**Note:** the Auto SDK only supports updates to `DTMF_SUPPORTED` to enable or disable `SendDTMF`. + +Use one of the following methods to update the device configuration: + +* Use intent. Your application can send messages with a particular intent to the AACS Telephony Service to update the device configuration. Specify the attributes of the intent as follows: + + * Action is `com.amazon.aacstelephony.updateDeviceConfiguration`. + * Category is `com.amazon.aacstelephony`. + * Extras is: +``` + { + "deviceProperty": "", + "enable": + } +``` + +* Use a direct API call. This method is applicable only if you put the AACS Telephony Library in your application. The following code shows how to use the `PhoneCallController` API: + +```java + // Instantiate PhoneCallController + PhoneCallController phoneCallController = new PhoneCallController(context, aacsMessageSender); + phoneCallController.updateDeviceConfiguration(deviceProperty, enable); +``` + +>**Tip:** All the key constants, intent actions, and categories are defined in the `TelephonyConstants` class in the AACS Constants Library. + +## (Optional) Receiving Device Connection Changes + +The AACS Telephony Library not only detects and reports the Bluetooth connection state changes to the Engine (and subsequently Alexa), but can also broadcast the changes to your application if you find the broadcasts useful. Whenever `BluetoothStateListener` in the AACS Telephony Service detects a connection change with the Phone Book Access Profile (PBAP), it sends an intent with the device name and address to the listeners. The attributes of the intent with the connection information are as follows: + +* Action is `com.amazon.aacstelephony.bluetooth.connected` for connected events and +`com.amazon.aacstelephony.bluetooth.disconnected` for disconnected events. +* Category is `com.amazon.aacstelephony`. +* Extras is +``` + { + "deviceName": "", + "deviceAddress": "" + } +``` + +## Known Issue + +* When there is an active phone call, and if the application (either AACS or your application) containing AACS Telephony Library crashes, when it comes back, the InCallService defined in AACS Telephony Library would not automatically rebound, and therefore you cannot control the active call with Alexa. This is due to the InCallService in this library is not with the default dialer. New calls after the crash would trigger the InCallService to rebind to the system and phone call controlling would work as usual. Besides, reconnecting Bluetooth also triggers a rebinding in this case. \ No newline at end of file diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/.gitignore b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/.gitignore similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/.gitignore rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/.gitignore diff --git a/aacs/android/app-components/alexa-auto-telephony/aacstelephony/build.gradle b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/build.gradle new file mode 100644 index 000000000..0b8c423ac --- /dev/null +++ b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/build.gradle @@ -0,0 +1,52 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 27 + versionCode 1 + versionName "4.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests.returnDefaultValues = true + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.aar']) + implementation project(':aacsconstants') + implementation project(':aacscommonutils') + implementation project(':aacsipc') + + implementation 'androidx.appcompat:appcompat:1.2.0' + + /** Test Dependencies **/ + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:1.10.19' + testImplementation 'org.powermock:powermock-api-mockito:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4:1.6.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.0' + androidTestImplementation 'androidx.test:runner:1.1.0' + androidTestImplementation 'org.mockito:mockito-android:2.22.0' + +} diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/consumer-rules.pro b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/consumer-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/consumer-rules.pro rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/consumer-rules.pro diff --git a/platforms/android/app-components/alexa-auto-media-player/proguard-rules.pro b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-media-player/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/androidTest/java/com/amazon/aacstelephony/ExampleInstrumentedTest.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/androidTest/java/com/amazon/aacstelephony/ExampleInstrumentedTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/androidTest/java/com/amazon/aacstelephony/ExampleInstrumentedTest.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/androidTest/java/com/amazon/aacstelephony/ExampleInstrumentedTest.java diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java similarity index 85% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java index bfdce19eb..bedee3807 100644 --- a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java +++ b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/AACSTelephonyService.java @@ -61,7 +61,6 @@ public class AACSTelephonyService extends Service { private AACSMessageSender mAACSMessageSender; private PhoneCallController mPhoneCallController; private BluetoothStateListener mBluetoothStateListener; - private boolean isExpectingPhoneAccount; public AACSTelephonyService() { mServiceLifecycle = new ServiceLifecycle(); @@ -106,22 +105,6 @@ public void onDestroy() { } private void handleIntent(Intent intent) { - // Non-AASB directive intents - - if (TelephonyConstants.ACTION_REPLY_PHONE_ACCOUNT_HANDLER.equals(intent.getAction()) - && isExpectingPhoneAccount) { - if (intent.getBooleanExtra(TelephonyConstants.ISREDIAL, false)) { - Log.i(TAG, "about to redial"); - redial(intent); - } else { - Log.i(TAG, "about to dial"); - dial(intent); - } - Log.i(TAG, "is redial? " + intent.getBooleanExtra(TelephonyConstants.ISREDIAL, false)); - isExpectingPhoneAccount = false; - return; - } - if (TelephonyConstants.ACTION_UPDATE_DEVICE_COFIGURATION.equals(intent.getAction())) { String property = intent.getStringExtra(TelephonyConstants.DEVICE_PROPERTY); boolean enable = intent.getBooleanExtra(TelephonyConstants.ENABLE, false); @@ -177,15 +160,12 @@ private void handleIntent(Intent intent) { } } - public void dial(Intent intent) { - Bundle bundle = intent.getBundleExtra(TelephonyConstants.PHONE_ACCOUNT_BUNDLE); - PhoneAccountHandle handle = bundle.getParcelable(TelephonyConstants.PHONE_ACCOUNT_HANDLE); - String callId = intent.getStringExtra(TelephonyConstants.CALLID); - String callNumber = intent.getStringExtra(TelephonyConstants.CALLERID); + public void dial(PhoneAccountHandle handle, String callId, String callNumber) { mPhoneCallController.dial(callId, callNumber, handle); } public void queryPhoneAccount(String payload, Boolean isRedial) { + PhoneAccountHandle selectedPhoneAccount = mPhoneCallController.getPhoneAccount(); try { String callNumber = ""; String payloadString = new JSONObject(payload).getString(AACSConstants.PAYLOAD); @@ -198,32 +178,18 @@ public void queryPhoneAccount(String payload, Boolean isRedial) { callNumber = defaultAddress.getString("value"); } } - Intent intent = new Intent(TelephonyConstants.ACTION_QUERY_PHONE_ACCOUNT_HANDLER); - intent.addCategory(TelephonyConstants.CATEGORY_AACS_TELEPHONY); - - List targets = - AACSComponentRegistryUtil.queryPackageManager(this, intent, Constants.AACS_TELEPHONY_PERMISSION); - if (targets == null) { - Log.e(TAG, "No app is listening to the query phone account intent"); - return; + if (!isRedial) { + dial(selectedPhoneAccount, callId, callNumber); + } else { + redial(selectedPhoneAccount, callId); } - intent.putExtra(TelephonyConstants.CALLERID, callNumber); - intent.putExtra(TelephonyConstants.CALLID, callId); - intent.putExtra(TelephonyConstants.ISREDIAL, isRedial); - - Util.sendNonAASBIntent(this, targets, intent); - Log.v(TAG, "Query phone account intent sent. "); - - isExpectingPhoneAccount = true; } catch (JSONException e) { Log.e(TAG, "Error parsing Dial directive payload: " + e.getMessage()); + } } - public void redial(Intent intent) { - Bundle bundle = intent.getBundleExtra(TelephonyConstants.PHONE_ACCOUNT_BUNDLE); - PhoneAccountHandle handle = bundle.getParcelable(TelephonyConstants.PHONE_ACCOUNT_HANDLE); - String callId = intent.getStringExtra(TelephonyConstants.CALLID); + public void redial(PhoneAccountHandle handle, String callId) { mPhoneCallController.redial(callId, handle); } diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java similarity index 98% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java index 5533635e2..9e0782c5b 100644 --- a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java +++ b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/BluetoothStateListener.java @@ -63,6 +63,7 @@ public void initialConnectionCheck(@NonNull Context context) { for (BluetoothDevice device : pairedDevices) { Util.broadcastBluetoothState(context, true, device.getName(), device.getAddress()); } + Util.broadcastConnectionCheckCompleted(context); } } diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallMap.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallMap.java similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallMap.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallMap.java diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallStateListener.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallStateListener.java similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallStateListener.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/CallStateListener.java diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Constants.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Constants.java similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Constants.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Constants.java diff --git a/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/PhoneCallController.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/PhoneCallController.java new file mode 100644 index 000000000..868e5a990 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/PhoneCallController.java @@ -0,0 +1,387 @@ +/* + * Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file 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.amazon.aacstelephony; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.provider.CallLog; +import android.provider.ContactsContract; +import android.telecom.Call; +import android.telecom.InCallService; +import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; +import android.telecom.TelecomManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; + +import com.amazon.aacsconstants.AACSConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.TelephonyConstants; +import com.amazon.aacsconstants.Topic; +import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; + +import org.json.JSONStringer; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class PhoneCallController extends InCallService { + private static final String TAG = AACSConstants.AACS + "-" + + "AACSTelephonyService" + + "-" + PhoneCallController.class.getSimpleName(); + private Context mTelephonyServiceContext; + private TelecomManager mTelecomManager; + private AACSMessageSender mAACSMessageSender; + private static CallMap mCallMap; + + /** + * Constructor for the system when binding InCallService + */ + public PhoneCallController() { + Log.i(TAG, "InCallService created"); + AACSSender aacsSender = new AACSSender(); + mAACSMessageSender = new AACSMessageSender(new WeakReference<>(this), aacsSender); + } + + /** + * Constructor for any non-system components + * @param context Context of AACSTelephonyService + */ + public PhoneCallController(@NonNull Context context, @NonNull AACSMessageSender aacsMessageSender) { + mTelephonyServiceContext = context; + mAACSMessageSender = aacsMessageSender; + if (mCallMap == null) + mCallMap = new CallMap(); + if (mTelecomManager == null) + mTelecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); + } + + PhoneCallController( + @NonNull Context context, @NonNull AACSMessageSender aacsMessageSender, TelecomManager telecomManager) { + this(context, aacsMessageSender); + if (telecomManager != null) + mTelecomManager = telecomManager; + } + + /** + * Platform implementation for Alexa initiating a call + * Suppressing the "MissingPermission" error as AACS currently doesn't request any permissions from the user + * @param callId Call Id in the PhoneCallController.Dial directive + * @param callNumber Number to be dialed + * @param handle Phone account handle to be used to make the call + */ + @SuppressLint("MissingPermission") + void dial(String callId, String callNumber, PhoneAccountHandle handle) { + Log.d(TAG, "dial"); + if (Util.bluetoothNotConnected()) { + Log.e(TAG, "Bluetooth disconnected, the call will not be initiated."); + Util.reportCallFailure( + mAACSMessageSender, callId, TelephonyConstants.ErrorCode.OTHER, "Bluetooth disconnected"); + return; + } + + if (handle == null) { + Log.e(TAG, "Invalid phoneAccountHandle, the call will not be initiated."); + Util.reportCallFailure(mAACSMessageSender, callId, TelephonyConstants.ErrorCode.NO_CARRIER, ""); + return; + } + + mCallMap.addCall(null, callId, callNumber); + Uri uri = Uri.fromParts(PhoneAccount.SCHEME_TEL, callNumber, null); + Bundle extras = new Bundle(); + extras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, handle); + + mTelecomManager.placeCall(uri, extras); + } + + /** + * Platform implementation for redialing + * Suppressing the "MissingPermission" error as AACS currently doesn't request any permissions from the user + * @param callId Call Id in the PhoneCallController.Redial directive + * @param handle Phone account handle to be used to make the call + */ + @SuppressLint("MissingPermission") + void redial(String callId, PhoneAccountHandle handle) { + Log.d(TAG, "redial"); + String callNumber = CallLog.Calls.getLastOutgoingCall(mTelephonyServiceContext); + if (callNumber.isEmpty()) { + Log.e(TAG, "Last dialed number is not available"); + Util.reportCallFailure(mAACSMessageSender, callId, TelephonyConstants.ErrorCode.NO_NUMBER_FOR_REDIAL, ""); + return; + } + + dial(callId, callNumber, handle); + } + + /** + * Platform implementation for answering the current incoming call + * @param callId Call Id of the call to be answered + */ + void answer(String callId) { + Log.d(TAG, "answer"); + if (Util.bluetoothNotConnected()) { + Log.e(TAG, "Bluetooth disconnected"); + Util.reportCallFailure( + mAACSMessageSender, callId, TelephonyConstants.ErrorCode.OTHER, "Bluetooth disconnected"); + return; + } + + Call currentCall = mCallMap.getCall(callId); + if (currentCall == null) { + Log.e(TAG, String.format("Call object with callId=%s not found", callId)); + Util.reportCallFailure(mAACSMessageSender, callId, TelephonyConstants.ErrorCode.OTHER, + "No matching call Id in current calls"); + return; + } + + Log.v(TAG, "Answering call with callId " + callId); + currentCall.answer(0); + } + + /** + * Platform implementation for Alexa stopping the current call + * @param callId Call with this Call Id to be stopped + */ + void stop(String callId) { + Log.d(TAG, "stop"); + if (Util.bluetoothNotConnected()) { + Log.e(TAG, "Bluetooth disconnected"); + Util.reportCallFailure( + mAACSMessageSender, callId, TelephonyConstants.ErrorCode.OTHER, "Bluetooth disconnected"); + return; + } + + Call currentCall = mCallMap.getCall(callId); + if (currentCall == null) { + Log.e(TAG, String.format("Call object with callId=%s not found", callId)); + Util.reportCallFailure(mAACSMessageSender, callId, TelephonyConstants.ErrorCode.OTHER, + "No matching call Id in current calls"); + return; + } + + if (currentCall.getState() == Call.STATE_RINGING) { + Log.v(TAG, "Rejecting the current incoming call.."); + currentCall.reject(false, null); + } else { + Log.v(TAG, "Stopping the current active call.."); + currentCall.disconnect(); + } + } + + /** + * Platform implementation for sending DTMF signal to the current call + * @param callId Call with this Call Id to get the signal + * @param signal The signal to be sent + */ + void sendDTMF(String callId, String signal) { + Log.d(TAG, "sendDTMF"); + if (Util.bluetoothNotConnected()) { + Log.e(TAG, "Bluetooth disconnected"); + Util.reportSendDTMFResult( + false, mAACSMessageSender, callId, Constants.SendDTMFError.DTMF_FAILED, "Bluetooth disconnected"); + return; + } + + Call currentCall = mCallMap.getCall(callId); + if (currentCall == null) { + Log.e(TAG, "Call object not found"); + Util.reportSendDTMFResult( + false, mAACSMessageSender, callId, Constants.SendDTMFError.CALL_NOT_IN_PROGRESS, "No active call"); + return; + } + + Log.d(TAG, "Sending DTMF..." + signal); + for (char digit : signal.toCharArray()) { + currentCall.playDtmfTone(digit); + currentCall.stopDtmfTone(); + } + Util.reportSendDTMFResult(true, mAACSMessageSender, callId, null, null); + } + + void callIdReceived(String callId) { + Log.d(TAG, "callIdReceived"); + + CallMap.CallInfo currentCallInfo = mCallMap.getCallInfoWithoutCallId(); + if (currentCallInfo == null) { + Log.e(TAG, "No call that is expecting Call Id found"); + return; + } + + String currentCallerId = currentCallInfo.getCallerId(); + Call currentCall = currentCallInfo.getCall(); + + Util.publishCallStateToAACS(currentCall.getState(), mAACSMessageSender, callId, currentCallerId); + Call.Callback callStateCallback = + new CallStateListener(mTelephonyServiceContext, callId, currentCallerId, mAACSMessageSender); + currentCall.registerCallback(callStateCallback); + + // Add call to the map + mCallMap.addCallback(currentCall, callStateCallback); + mCallMap.addCall(currentCall, callId, currentCallerId); + } + + boolean initialCallStateCheck() { + Log.d(TAG, "initialCallStateCheck"); + + HashMap callIdCallInfoMap = mCallMap.getCallIdCallInfoMap(); + Log.i(TAG, "Active calls when AACS starts " + callIdCallInfoMap.size()); + if (callIdCallInfoMap.size() > 0) { + Util.checkAndReportCurrentCalls(callIdCallInfoMap, mAACSMessageSender); + return true; + } + + return false; + } + + /** + * Public API which can either be called by the client or by AACSTelephonyService upon receiving + * related intent from the client to update device configuration. + * Currently Auto SDK only supports one property: DTMF_SUPPORTED (true/false) + * @param deviceProperty + * @param value + */ + public void updateDeviceConfiguration(String deviceProperty, boolean value) { + Log.d(TAG, "updateDeviceConfiguration"); + try { + String configurationMap = + new JSONStringer().object().key(deviceProperty).value(value).endObject().toString(); + String payload = + new JSONStringer().object().key("configurationMap").value(configurationMap).endObject().toString(); + + mAACSMessageSender.sendMessage( + Topic.PHONE_CALL_CONTROLLER, Action.PhoneCallController.DEVICE_CONFIGURATION_UPDATED, payload); + } catch (Exception e) { + Log.e(TAG, "Failed to create createCallId JSON payload." + e.getMessage()); + } + } + + public PhoneAccountHandle getPhoneAccount() { + if (mTelephonyServiceContext.checkSelfPermission(android.Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) { + Log.e(TAG,"Failed to get the outgoing phone account due to missing READ_PHONE_STATE permission"); + return null; + } + PhoneAccountHandle selectedHandle = mTelecomManager.getDefaultOutgoingPhoneAccount(PhoneAccount.SCHEME_TEL); + + // if getDefaultOutgoingPhoneAccount returns null, call getCallCapablePhoneAccounts to get all the valid phone accounts. + // if there is only one valid account, then return the handle for that account. Otherwise, return null. + if (selectedHandle == null) { + Log.i(TAG, "getDefaultOutgoingAccount returns null, calling getCallCapablePhoneAccounts"); + List validHandles = new ArrayList<>(); + for (PhoneAccountHandle handle : mTelecomManager.getCallCapablePhoneAccounts()) { + PhoneAccount phoneAccount = mTelecomManager.getPhoneAccount(handle); + if (phoneAccount == null) continue; + // verify the phone account is not an emergency account + if (phoneAccount.getShortDescription() == null || !phoneAccount.getShortDescription().toString().contains("Emergency")) { + validHandles.add(handle); + } + } + if (validHandles.size() == 1) selectedHandle = validHandles.get(0); + } + return selectedHandle; + } + + @Override + public void onCallAdded(Call call) { + Log.d(TAG, "onCallAdded"); + int callState = call.getState(); + + if (mCallMap == null) { + mCallMap = new CallMap(); + } + + // Incoming call + if (callState == Call.STATE_RINGING) { + Util.sendQueryCallIdRequest(mAACSMessageSender); + String currentCallerId = call.getDetails().getHandle().getSchemeSpecificPart(); + mCallMap.addCall(call, Constants.CallState.INBOUND_RINGING, currentCallerId); + + Log.v(TAG, "New incoming call..."); + return; + } + + // Already in an active call + if (callState == Call.STATE_ACTIVE) { + Util.sendQueryCallIdRequest(mAACSMessageSender); + String currentCallerId = call.getDetails().getHandle().getSchemeSpecificPart(); + mCallMap.addCall(call, Constants.CallState.ACTIVE, currentCallerId); + + Log.v(TAG, "New active call..."); + return; + } + + // Outgoing calls + if (callState == Call.STATE_CONNECTING || callState == Call.STATE_DIALING) { + CallMap.CallInfo outgoingCallInfo = mCallMap.getOutgoingCallInfo(); + Log.v(TAG, "New outgoing call..."); + + if (outgoingCallInfo != null) { + // Alexa initiates the call + String callerId = outgoingCallInfo.getCallerId(); + String callId = outgoingCallInfo.getCallId(); + + Call.Callback callStateCallback = new CallStateListener(this, callId, callerId, mAACSMessageSender); + call.registerCallback(callStateCallback); + + mCallMap.setCall(callId, call); + mCallMap.addCallback(call, callStateCallback); + + } else { + // User initiates the call from head unit or phone + Util.sendQueryCallIdRequest(mAACSMessageSender); + String currentCallerId = call.getDetails().getHandle().getSchemeSpecificPart(); + mCallMap.addCall(call, Constants.CallState.DIALING, currentCallerId); + } + } + } + + @Override + public void onCallRemoved(Call call) { + Log.d(TAG, "onCallRemoved"); + + Call.Callback callStateCallback = mCallMap.removeCallback(call); + mCallMap.removeCall(call); + + if (callStateCallback != null) { + call.unregisterCallback(callStateCallback); + } else { + Log.w(TAG, "Callback is not found for the call"); + } + + HashMap callIdCallInfoMap = mCallMap.getCallIdCallInfoMap(); + if (callIdCallInfoMap.size() > 0) { + Util.checkAndReportCurrentCalls(callIdCallInfoMap, mAACSMessageSender); + } + } + + CallMap getCallMap() { + Log.d(TAG, "getCallMap"); + return mCallMap; + } + + void cleanUp() { + Log.d(TAG, "cleanUp"); + mCallMap.clear(); + mCallMap = null; + } +} diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java similarity index 92% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java rename to aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java index 7c7bb7512..ef5506c9e 100644 --- a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java +++ b/aacs/android/app-components/alexa-auto-telephony/aacstelephony/src/main/java/com/amazon/aacstelephony/Util.java @@ -171,6 +171,23 @@ static void broadcastBluetoothState( sendNonAASBIntent(context, listeners, intent); } + static void broadcastConnectionCheckCompleted( + @NonNull Context context) { + String action = TelephonyConstants.ACTION_BLUETOOTH_STATE_CONNECTION_CHECK_COMPLETED; + Intent intent = new Intent(action); + intent.addCategory(TelephonyConstants.CATEGORY_AACS_TELEPHONY); + + List listeners = + AACSComponentRegistryUtil.queryPackageManager(context, intent, Constants.AACS_TELEPHONY_PERMISSION); + + if (listeners == null) { + Log.e(TAG, "No listeners to the bluetooth connection check completed events"); + return; + } + + sendNonAASBIntent(context, listeners, intent); + } + static void checkAndReportCurrentCalls(@NonNull HashMap callIdCallInfoMap, @NonNull AACSMessageSender aacsMessageSender) { for (String callId : callIdCallInfoMap.keySet()) { @@ -186,6 +203,10 @@ static void checkAndReportCurrentCalls(@NonNull HashMap + variant.outputs.all { + def project = "alexa-auto-templateruntime-renderer" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(path: ':aacscommonutils') + implementation project(path: ':aacsconstants') + implementation project(path: ':alexa-auto-apis') + implementation project(':alexa-auto-apps-common-ui') + implementation project(':alexa-auto-apps-common-util') + implementation project(':aacsipc') + + implementation deps.androidx_appcompat + implementation deps.androidx_recycler_view + implementation deps.androidx_constraint + + //Picasso + implementation 'com.squareup.picasso:picasso:2.71828' + + // Dagger + implementation deps.dagger + annotationProcessor deps.dagger_compiler + + // Glide + implementation deps.glide + annotationProcessor deps.glide_compiler + + //Eventbus + implementation deps.eventbus + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.mockito_inline + testImplementation deps.androidx_test_core + testImplementation deps.androidx_arch_core_testing + testImplementation deps.roboelectric +} diff --git a/platforms/android/app-components/alexa-auto-navigation/proguard-rules.pro b/aacs/android/app-components/alexa-auto-templateruntime-renderer/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-navigation/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AACSModule.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AACSModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AACSModule.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AACSModule.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AndroidModule.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AndroidModule.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AndroidModule.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/AndroidModule.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/TemplateRuntimeComponent.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/TemplateRuntimeComponent.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/TemplateRuntimeComponent.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/dependencies/TemplateRuntimeComponent.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiver.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiver.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiver.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaVoiceoverCompletedMessage.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaVoiceoverCompletedMessage.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaVoiceoverCompletedMessage.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaVoiceoverCompletedMessage.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiver.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiver.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiver.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapter.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapter.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapter.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapter.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java similarity index 97% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java index 66f402aa3..86d0e7ed2 100644 --- a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java +++ b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandler.java @@ -11,7 +11,9 @@ import androidx.annotation.VisibleForTesting; import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.PagerSnapHelper; import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SnapHelper; import com.amazon.alexa.auto.aacs.common.AACSMessage; import com.amazon.alexa.auto.aacs.common.TemplateRuntimeMessages; @@ -89,6 +91,8 @@ void renderWeatherView(ViewGroup viewGroup, WeatherTemplate weatherTemplate) { RecyclerView recyclerView = inflatedView.findViewById(R.id.weather_recycler_view); recyclerView.setLayoutManager(layoutManager); + SnapHelper snapHelper = new PagerSnapHelper(); + snapHelper.attachToRecyclerView(recyclerView); recyclerView.addItemDecoration(new CirclePageIndicatorDecoration()); recyclerView.setAdapter(adapter); recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/display_card_background.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/display_card_background.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/display_card_background.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/display_card_background.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/ic_cancel.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/ic_cancel.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/ic_cancel.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/drawable/ic_cancel.xml diff --git a/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather.xml new file mode 100644 index 000000000..5ef867424 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_current.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_current.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_current.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_current.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast_day.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast_day.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast_day.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/layout/weather_forecast_day.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values-land/dimens.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values-land/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values-land/dimens.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values-land/dimens.xml diff --git a/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/dimens.xml new file mode 100644 index 000000000..ecfbcaac6 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/dimens.xml @@ -0,0 +1,59 @@ + + + + 0dp + 800dp + 15dp + 15dp + 45dp + 65dp + 46dp + 15dp + 20dp + + + 700dp + 80dp + 5dp + 30sp + 24sp + 10dp + 40dp + 300dp + 40dp + 20dp + + 225dp + 225dp + 175dp + 100dp + 35dp + 50dp + 75sp + 30dp + 25dp + 40dp + 70dp + 20dp + 20dp + 75dp + 50dp + 20dp + 40dp + 40sp + + 21dp + 25dp + 20dp + 125dp + 125dp + 70dp + 60dp + 35dp + 30sp + 60dp + 50dp + 10dp + 10dp + 30sp + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/ids.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/ids.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/ids.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/ids.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/styles.xml b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/styles.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/styles.xml rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/main/res/values/styles.xml diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/common/TestResourceFileReader.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/common/TestResourceFileReader.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/common/TestResourceFileReader.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/common/TestResourceFileReader.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiverTest.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiverTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiverTest.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/AlexaStateChangeReceiverTest.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiverTest.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiverTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiverTest.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/receiver/TemplateRuntimeReceiverTest.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapterTest.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapterTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapterTest.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherAdapterTest.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandlerTest.java b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandlerTest.java similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandlerTest.java rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/java/com/amazon/alexa/auto/templateruntime/weather/WeatherDirectiveHandlerTest.java diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/ClearTemplate.json b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/ClearTemplate.json similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/ClearTemplate.json rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/ClearTemplate.json diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedIdle.json b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedIdle.json similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedIdle.json rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedIdle.json diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedListening.json b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedListening.json similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedListening.json rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/DialogStateChangedListening.json diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/RenderTemplateWeather.json b/aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/RenderTemplateWeather.json similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/RenderTemplateWeather.json rename to aacs/android/app-components/alexa-auto-templateruntime-renderer/src/test/resources/aacs/RenderTemplateWeather.json diff --git a/aacs/android/app-components/alexa-auto-tts/README.md b/aacs/android/app-components/alexa-auto-tts/README.md new file mode 100644 index 000000000..a3c3e4558 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-tts/README.md @@ -0,0 +1,181 @@ +# Text-to-Speech Service +Text-to-Speech (TTS) Service provides an implementation on the Android platform to synthesize non-Alexa speech on demand from text. It implements the Android abstract `TextToSpeechService` class, which is part of Android TTS framework APIs, and in the backend uses the Text-to-Speech functionality provided by the Auto SDK. Android applications can interact with these standard Android TTS APIs to convert text to speech. + + +## Table of Contents +- [Overview](#overview) +- [Building the Library](#building-the-library) +- [Architecture](#architecture) +- [Configuration](#configuration) +- [Sample Usage](#sample-usage) + - [Initialization](#initialization) + - [Get Capabilities](#get-capabilities) + - [Synthesize Audio](#synthesize-audio) +- [Known Issues](#known-issues) + + +## Overview + +Text-to-Speech Service implements [TextToSpeechService](https://developer.android.com/reference/android/speech/tts/TextToSpeechService), which is an abstract base class for TTS engine implementations. The following list describes the responsibilities of the service and the Android TTS framework: + +* The service is responsible for: + + * retrieving the TTS capabilities from AACS + * preparing the TTS audio and vending out the stream to the Android TTS framework APIs + +* The Android TTS framework is responsible for: + + * handling the states of TTS requests + * playing out the audio + * saving the audio to file + +The Text-to-Speech Service communicates with AACS to get the available locales and fetch the synthesized audio stream. Therefore, AACS must be started, configured, and running in connected state to ensure the Text-to-Speech Service can generate the designated TTS audio correctly. + +## Building the Library +Text-to-Speech Service is built as an Android Archive (AAR) to be included in your application along with the AACS AAR. +You can build the library locally using the following steps: + 1) Enter the following command to change the directory: + ~~~ + cd ${AAC_SDK_HOME}/aacs/android/sample-app + ~~~ + 2) Enter the following command to build the TTS library: + ~~~ + ./gradlew :alexa-auto-tts:assembleRelease + ~~~ + Replace `assembleRelease` with `assembleDebug` if you want to build the debug version of the library. The generated AAR is available at `alexa-auto-sdk/aacs/android/app-components/alexa-auto-tts/aacstts/build/outputs/aar`. + You must include the `AACSIPC`, `AACSConstants`, `AACSCommonUtils`, `AACS` and `Auto SDK` AARs in your application to use with the AACS TTS AAR. + +AACS TTS is by default enabled in the AACS Sample App. See the [AACS Sample App README](../../sample-app/README.md#building-and-signing-the-aacs-sample-app-apk) for build instructions. +>**Important!** The Text-to-Speech Service requires the Local Voice Control and Alexa Custom Assistant extensions to function. + +## Architecture +The following diagram shows the high-level architecture of TTS Service and AACS. The blue box in the diagram represents the Text-to-Speech Service and the white boxes in the diagram represent the other components developed by Amazon. These components are all packaged in AARs to be added along with AACS AAR into AACS Sample App or your application. The other boxes represent components that do not belong to Amazon: The yellow boxes represent the components from the Android TTS framework, and the green box represents the OEM application using Android TTS APIs. + +
+ +
+ +1. **Android Application** is owned by OEMs to handle the Text-to-Speech interaction with the end user by creating an instance of the `TextToSpeech` object and issuing Text-to-Speech requests. +2. **TextToSpeech** is the Facade class that acts as a bridge between the Text-to-Speech application, which issues the TTS requests, and the underlying `TextToSpeechService`, which renders the response. See [Android documentation for TextToSpeech](https://developer.android.com/reference/android/speech/tts/TextToSpeech) here. +3. **TextToSpeechService** is an abstract base class for TTS engine implementations. For more information about this class, see [Android documentation for TextToSpeechService](https://developer.android.com/reference/android/speech/tts/TextToSpeechService). +4. **AmazonTextToSpeechService** is the actual implementation of `TextToSpeechService` that communicates with AACS via the IPC library to issue Text-to-Speech requests. +5. **Core Service** is responsible for accepting TTS requests from `AmazonTextToSpeechService` and for routing those requests to the Auto SDK's `TextToSpeech` platform interface, which issues a request to the appropriate TTS provider. For information about TTS providers, see [TextToSpeechProvider module README](../../../../modules/text-to-speech-provider/README.md). + + +## Configuration +To specify the intent targets for AASB message intents from AACS, follow the instructions in [AACS README](../../README.md). The TTS Service defines a list of intent filters in its Android manifest to subscribe to specific AASB message intents. If your application uses static configuration to specify the target for AASB topics, provide the following information as part of the AACS configuration to enable the communication between TTS Service and AACS. +​ +```java +{ ... + "aacs.general": { + "intentTargets": { + "AASB": { + "type": [ + "RECEIVER" + ], + "package": [ + "com.amazon.alexaautoclientservice" + ], + "class": [ + "com.amazon.aacstts.TTSIntentReceiver" + ] + }, + "AlexaClient": { + "type": [ + "RECEIVER" + ], + "package": [ + "com.amazon.alexaautoclientservice" + ], + "class": [ + "com.amazon.aacstts.TTSIntentReceiver" + ] + }, + "TextToSpeech": { + "type": [ + "RECEIVER" + ], + "package": [ + "com.amazon.alexaautoclientservice" + ], + "class": [ + "com.amazon.aacstts.TTSIntentReceiver" + ] + }, + ... + } +``` +TTS Service subscribes to the AASB messages with the `AASB`, `AlexaClient`, and `TextToSpeech` topics by using a broadcast receiver. Make sure that you properly populate the type, the package name, and the class name into the `intentTargets` JSON node for these topics, as shown in the JSON example above. + +## Sample Usage +Your application uses the Text-to-Speech Service in the same way as it would use any TTS engine. To synthesize speech, the application must create a `TextToSpeech` object and then set the input text. The application can also specify the speech pitch and rate. + +### Initialization +Initialize the Text-to-Speech Service in one of two ways: +* If the Android application creates a `TextToSpeech` object without specifying the package name of the TTS engine to use, the default TTS engine is used. +```java +// Create the TextToSpeech using the default engine +TextToSpeech textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status != TextToSpeech.ERROR) { + // do things upon TextToSpeechService is initialized + } + } +}); +``` +You can change the default engine to Text-to-Speech Service by following these steps: + + 1. Open the Android Settings menu and navigate "Preferred Engine" as follows: + + app → “General Management” → “Language and Input” → "Text-to-Speech" → "Preferred Engine" + + 2. Choose "Amazon Text-to-Speech Engine" in the list. + +* The Android application can also directly create Text-to-Speech Service by specifying the package name "com.amazon.alexaautoclientservice" when creating the `TextToSpeech` object. +```java +// Create the TextToSpeech by specifying the package name of the TextToSpeechService +TextToSpeech textToSpeech = new TextToSpeech(getApplicationContext(), new TextToSpeech.OnInitListener() { + @Override + public void onInit(int status) { + if (status != TextToSpeech.ERROR) { + // do things upon TextToSpeechService is initialized + } + } +}, "com.amazon.alexaautoclientservice"); +``` +You must initiate TTS Service at least once to warm up the language cache before making any synthesis requests. + +### Get Capabilities +The Android applications may query the Text-to-Speech Service to get the available voices. For information about voices, see [Android Voice class](https://developer.android.com/reference/android/speech/tts/Voice). For information about languages, see [Locale class](https://developer.android.com/reference/java/util/Locale). +The following examples show how to get the available voices and languages from the Engine: +```java +// Query the engine about the set of available voices +Set voices = textToSpeech.getVoices(); +// Query the engine about the set of available languages. +Set locales = textToSpeech.getAvailableLanguages(); +// Check if the specified language as represented by the Locale is available and supported. +int supported = textToSpeech.isLanguageAvailable(Locale.US) +``` + +### Synthesize Audio +The Android TTS framework provides two ways of synthesizing TTS audio: + +* **Play out the audio immediately:** The Android applications may call the `speak` API. +```java +public int speak (CharSequence text, + int queueMode, + Bundle params, + String utteranceId) +``` +* **Save to a WAV file:** The Android applications may call the `synthesizeToFile` API. +```java +public int synthesizeToFile (CharSequence text, + Bundle params, + File file, + String utteranceId) +``` + +## Known Issues +Conversion of MP3 to RAW Audio for TTS on the X86 platform is not yet supported. + diff --git a/aacs/android/app-components/alexa-auto-tts/aacstts/.gitignore b/aacs/android/app-components/alexa-auto-tts/aacstts/.gitignore new file mode 100644 index 000000000..ae66af5e5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-tts/aacstts/.gitignore @@ -0,0 +1,8 @@ +.gradle/ +.idea/ +build/ +gradle/ +gradlew +gradlew.bat +local.properties +.DS_Store diff --git a/aacs/android/app-components/alexa-auto-tts/aacstts/build.gradle b/aacs/android/app-components/alexa-auto-tts/aacstts/build.gradle new file mode 100644 index 000000000..9e9003251 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-tts/aacstts/build.gradle @@ -0,0 +1,53 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "4.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + testOptions { + unitTests.returnDefaultValues = true + } +} + +dependencies { + compileOnly project(':aacsconstants') + compileOnly project(':aacsipc') + compileOnly project(':aacscommonutils') + + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation "androidx.preference:preference:1.0.0" + + /** Test Dependencies **/ + testImplementation 'junit:junit:4.12' + testImplementation 'org.powermock:powermock-api-mockito:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.2' + testImplementation 'org.powermock:powermock-module-junit4:1.6.2' + testImplementation 'org.json:json:20200518' + testImplementation 'org.mockito:mockito-core:1.10.19' + + androidTestImplementation 'androidx.test.ext:junit:1.1.0' + androidTestImplementation 'androidx.test:rules:1.1.0' + androidTestImplementation 'androidx.test:runner:1.1.0' + androidTestImplementation 'org.mockito:mockito-android:2.22.0' +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-settings/proguard-rules.pro b/aacs/android/app-components/alexa-auto-tts/aacstts/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-settings/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-tts/aacstts/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AACSUtil.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AACSUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AACSUtil.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AACSUtil.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AmazonTextToSpeechService.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AmazonTextToSpeechService.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AmazonTextToSpeechService.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AmazonTextToSpeechService.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AudioDecoder.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AudioDecoder.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AudioDecoder.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/AudioDecoder.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/ISO3CodeUtil.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/ISO3CodeUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/ISO3CodeUtil.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/ISO3CodeUtil.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/JSONUtil.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/JSONUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/JSONUtil.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/JSONUtil.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/MessageHandler.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/MessageHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/MessageHandler.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/MessageHandler.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/SynthesizeTextUtil.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/SynthesizeTextUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/SynthesizeTextUtil.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/SynthesizeTextUtil.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSConstants.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSConstants.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSConstants.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSConstants.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSIntentReceiver.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSIntentReceiver.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSIntentReceiver.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/TTSIntentReceiver.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AASBHandler.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AASBHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AASBHandler.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AASBHandler.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AlexaClientHandler.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AlexaClientHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AlexaClientHandler.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/AlexaClientHandler.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/IAACSMessageHandler.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/IAACSMessageHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/IAACSMessageHandler.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/IAACSMessageHandler.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/TTSHandler.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/TTSHandler.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/TTSHandler.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/handler/TTSHandler.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/GetCapabilitiesPayload.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/GetCapabilitiesPayload.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/GetCapabilitiesPayload.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/GetCapabilitiesPayload.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessageOptions.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessageOptions.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessageOptions.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessageOptions.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessagePayload.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessagePayload.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessagePayload.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/PrepareSpeechMessagePayload.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/ProviderVoiceItem.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/ProviderVoiceItem.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/ProviderVoiceItem.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/ProviderVoiceItem.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/TTSSynthesisFutureResponse.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/TTSSynthesisFutureResponse.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/TTSSynthesisFutureResponse.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/java/com/amazon/aacstts/models/TTSSynthesisFutureResponse.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-tts/aacstts/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AlexaClientHandlerTests.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AlexaClientHandlerTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AlexaClientHandlerTests.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AlexaClientHandlerTests.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AmazonTextToSpeechServiceTests.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AmazonTextToSpeechServiceTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AmazonTextToSpeechServiceTests.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/AmazonTextToSpeechServiceTests.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/SynthesizeTextUtilTests.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/SynthesizeTextUtilTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/SynthesizeTextUtilTests.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/SynthesizeTextUtilTests.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TTSHandlerTests.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TTSHandlerTests.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TTSHandlerTests.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TTSHandlerTests.java diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TestAACSUtil.java b/aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TestAACSUtil.java similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TestAACSUtil.java rename to aacs/android/app-components/alexa-auto-tts/aacstts/src/test/java/com/amazon/aacstts/TestAACSUtil.java diff --git a/platforms/android/app-components/alexa-auto-tts/assets/Android_TTS.png b/aacs/android/app-components/alexa-auto-tts/assets/Android_TTS.png similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/assets/Android_TTS.png rename to aacs/android/app-components/alexa-auto-tts/assets/Android_TTS.png diff --git a/platforms/android/app-components/alexa-auto-tts/assets/Android_TTS.xml b/aacs/android/app-components/alexa-auto-tts/assets/Android_TTS.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/assets/Android_TTS.xml rename to aacs/android/app-components/alexa-auto-tts/assets/Android_TTS.xml diff --git a/aacs/android/app-components/alexa-auto-tts/build.gradle b/aacs/android/app-components/alexa-auto-tts/build.gradle new file mode 100644 index 000000000..2cd2d0277 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-tts/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-carcontrol/gradle.properties b/aacs/android/app-components/alexa-auto-tts/gradle.properties similarity index 100% rename from platforms/android/app-components/alexa-auto-carcontrol/gradle.properties rename to aacs/android/app-components/alexa-auto-tts/gradle.properties diff --git a/platforms/android/app-components/alexa-auto-tts/settings.gradle b/aacs/android/app-components/alexa-auto-tts/settings.gradle similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/settings.gradle rename to aacs/android/app-components/alexa-auto-tts/settings.gradle diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/.gitignore b/aacs/android/app-components/alexa-auto-ux-restrictions/.gitignore new file mode 100644 index 000000000..ae66af5e5 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/.gitignore @@ -0,0 +1,8 @@ +.gradle/ +.idea/ +build/ +gradle/ +gradlew +gradlew.bat +local.properties +.DS_Store diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/README.md b/aacs/android/app-components/alexa-auto-ux-restrictions/README.md new file mode 100644 index 000000000..2ae1fa238 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/README.md @@ -0,0 +1,10 @@ +# Alexa Auto UX Restrictions + +The following list describes the purposes of this library: +* It provides `CarUxRestrictionsModule` and controls `CarUxRestrictionsController` life cycle. +* It provides default implementation for `CarUxRestrictionsController`, which initializes Android `CarUxRestrictionsManager`, registers and unregisters `OnUxRestrictionsChangedListener`. To use the default implemetation, it requires [Android car package](https://developer.android.com/reference/android/car/package-summary) exists on the device. OEM can also provide their own implementation for the car UX restrictions updates. + +This app component requires Android API 29. To build this component with AACS sample app, add the `-PenabledUXRestrictions` to your build command: +``` +./gradlew assembleLocalRelease -PenabledUXRestrictions +``` \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/build.gradle b/aacs/android/app-components/alexa-auto-ux-restrictions/build.gradle new file mode 100644 index 000000000..3d817c02c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/build.gradle @@ -0,0 +1,61 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 29 + defaultConfig { + minSdkVersion 26 + targetSdkVersion 29 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + useLibrary 'android.car' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + unitTests.includeAndroidResources = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-ux-restrictions" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } + +} + +dependencies { + implementation project(path: ':aacscommonutils') + implementation project(path: ':aacsconstants') + implementation project(path: ':alexa-auto-apis') + implementation project(path: ':alexa-auto-apps-common-util') + implementation project(':aacsipc') + + implementation deps.androidx_appcompat + implementation deps.androidx_constraint + implementation deps.rxjava3 + + // Dagger + implementation deps.dagger + annotationProcessor deps.dagger_compiler +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-setup/proguard-rules.pro b/aacs/android/app-components/alexa-auto-ux-restrictions/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-setup/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-ux-restrictions/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/AndroidManifest.xml new file mode 100644 index 000000000..ac2c9d553 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/AndroidManifest.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/assets/aacs-sample-app/modules-uxrestrictions.json b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/assets/aacs-sample-app/modules-uxrestrictions.json new file mode 100644 index 000000000..1f91c4abd --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/assets/aacs-sample-app/modules-uxrestrictions.json @@ -0,0 +1,5 @@ +{ + "module": { + "name": "com.amazon.alexa.auto.uxrestrictions.CarUxRestrictionsModule" + } +} diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/CarUxRestrictionsModule.java b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/CarUxRestrictionsModule.java new file mode 100644 index 000000000..6d092e73c --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/CarUxRestrictionsModule.java @@ -0,0 +1,136 @@ +package com.amazon.alexa.auto.uxrestrictions; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.util.Log; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.apis.app.AlexaApp; +import com.amazon.alexa.auto.apis.module.ModuleInterface; +import com.amazon.alexa.auto.apis.uxRestrictions.CarUxRestrictionsController; +import com.amazon.alexa.auto.apps.common.Constants; + +import org.json.JSONStringer; + +import java.lang.ref.WeakReference; + +import androidx.annotation.NonNull; +import io.reactivex.rxjava3.disposables.Disposable; + +public class CarUxRestrictionsModule implements ModuleInterface { + private static final String TAG = CarUxRestrictionsModule.class.getSimpleName(); + private static final String ANDROID_CAR_PACKAGE = "com.android.car"; + + private Context mContext; + private Disposable mCarUxRestrictionDisposable; + + @NonNull + private AACSMessageSender mAACSSender; + + @Override + public void initialize(Context context) { + Log.d(TAG, "initialize"); + mContext = context; + mAACSSender = new AACSMessageSender(new WeakReference(mContext), new AACSSender()); + initializeCarUxRestrictionsManager(); + } + + @Override + public void uninitialize(Context context) { + Log.d(TAG, "uninitialize"); + AlexaApp mApp = AlexaApp.from(context); + mApp.getRootComponent() + .getComponent(CarUxRestrictionsController.class) + .ifPresent(carUxRestrictionsController -> { + carUxRestrictionsController.unregisterListener(); + mApp.getRootComponent().deactivateScope(CarUxRestrictionsController.class); + }); + + if (mCarUxRestrictionDisposable != null) { + mCarUxRestrictionDisposable.dispose(); + mCarUxRestrictionDisposable = null; + } + } + + + /** + * Initialize car UX restrictions manager. If Android car package exists on the device, + * we can use Android car UX restrictions APIs to get current UX restriction value and subscribe to the restrictions update. + * Otherwise, OEM needs to provide their own implementation for car UX restrictions updates. + */ + private void initializeCarUxRestrictionsManager() { + AlexaApp mApp = AlexaApp.from(mContext); + if (isAndroidCardPackageExisted()) { + Log.d(TAG, "Android car library exists, initialize default CarUxRestrictionsController."); + mApp.getRootComponent().activateScope(new DefaultCarUxRestrictionsController(new WeakReference<>(mContext))); + mApp.getRootComponent() + .getComponent(CarUxRestrictionsController.class) + .ifPresent(CarUxRestrictionsController::registerListener); + } else { + Log.d(TAG, "Android Car UX Restrictions does not supported, please provide your own car UX restrictions implementation, and activate it as a scoped component"); + } + + observeCarUxRestrictionsChanges(); + } + + /** + * Check if Android car package exists on the device. + * + * @return true if exists, otherwise false. + */ + public boolean isAndroidCardPackageExisted() { + PackageManager pm = mContext.getPackageManager(); + try { + pm.getPackageInfo(ANDROID_CAR_PACKAGE, PackageManager.GET_META_DATA); + } catch (PackageManager.NameNotFoundException e) { + Log.d(TAG, "Android card package does not exist."); + return false; + } + return true; + } + + /** + * Observe Car UX restrictions changes on the device. + * Currently, we have one requirement regarding to sending AASB message with APL runtime property based on the UX restrictions updates. + */ + private void observeCarUxRestrictionsChanges() { + AlexaApp mApp = AlexaApp.from(mContext); + mApp.getRootComponent().getComponent(CarUxRestrictionsController.class).ifPresent(carUxRestrictionController -> { + mCarUxRestrictionDisposable = carUxRestrictionController.observeCarUxRestrictionChanged().subscribe(onUxRestrictionStatus -> { + String payload; + String drivingStateValue; + if (onUxRestrictionStatus.isRequiredUXRestriction()) { + drivingStateValue = Constants.APL_RUNTIME_PROPERTY_DRIVING_STATE_VALUE_MOVING; + } else { + drivingStateValue = Constants.APL_RUNTIME_PROPERTY_DRIVING_STATE_VALUE_PARKED; + } + + payload = new JSONStringer() + .object() + .key(Constants.APL_RUNTIME_PROPERTY_NAME_KEY) + .value(Constants.APL_RUNTIME_PROPERTY_DRIVING_STATE_NAME) + .key(Constants.APL_RUNTIME_PROPERTY_VALUE_KEY) + .value(drivingStateValue) + .endObject() + .toString(); + mAACSSender.sendMessage(Topic.APL, Action.APL.SET_PLATFORM_PROPERTY, payload); + + saveDrivingState(drivingStateValue); + }); + }); + } + + /** + * Saving APL driving state properties for rendering APL template with the updated APL driving state. + * @param drivingStateValue parked/driving + */ + private void saveDrivingState(String drivingStateValue) { + SharedPreferences.Editor editor = mContext.getSharedPreferences(Constants.APL_RUNTIME_PROPERTIES, 0).edit(); + editor.putString(Constants.APL_RUNTIME_PROPERTY_DRIVING_STATE_NAME, drivingStateValue); + editor.apply(); + } +} \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/DefaultCarUxRestrictionsController.java b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/DefaultCarUxRestrictionsController.java new file mode 100644 index 000000000..08e8ab990 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/java/com/amazon/alexa/auto/uxrestrictions/DefaultCarUxRestrictionsController.java @@ -0,0 +1,109 @@ +package com.amazon.alexa.auto.uxrestrictions; + +import android.car.Car; +import android.car.drivingstate.CarUxRestrictions; +import android.car.drivingstate.CarUxRestrictionsManager; +import android.content.Context; +import android.util.Log; + +import com.amazon.alexa.auto.apis.uxRestrictions.CarUxRestriction; +import com.amazon.alexa.auto.apis.uxRestrictions.CarUxRestrictionsController; +import com.amazon.alexa.auto.apis.uxRestrictions.CarUxRestrictionStatus; + +import java.lang.ref.WeakReference; + +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * Default implementation for car UX restrictions controller. It initializes Android CarUxRestrictionsManager, + * registers and unregisters OnUxRestrictionsChangedListener. + */ +public class DefaultCarUxRestrictionsController implements CarUxRestrictionsController { + private static final String TAG = DefaultCarUxRestrictionsController.class.getSimpleName(); + + //Android car UX restrictions code + private static final int UX_RESTRICTIONS_FULLY_RESTRICTED_CODE = 511; + private static final int UX_RESTRICTIONS_NO_RESTRICTION_CODE = 0; + + private static final String UX_RESTRICTIONS_FULLY_RESTRICTED_NAME = "UX_RESTRICTIONS_FULLY_RESTRICTED"; + private static final String UX_RESTRICTIONS_NO_RESTRICTION_NAME = "UX_RESTRICTIONS_NO_RESTRICTION"; + + private final WeakReference mContext; + private BehaviorSubject uxRestrictionStatusColdStream; + + private CarUxRestrictionsManager mCarUxRestrictionsManager; + private CarUxRestriction mCarUxRestriction; + private boolean mIsRequiresDistractionOptimization; + + public DefaultCarUxRestrictionsController(WeakReference context) { + mContext = context; + uxRestrictionStatusColdStream = BehaviorSubject.create(); + + initializeAndroidCarRestrictionsManager(); + } + + private void initializeAndroidCarRestrictionsManager() { + Car car = Car.createCar(mContext.get()); + if (car == null) { + Log.e(TAG, "Car Service is not available, Car object is null"); + } else { + mCarUxRestrictionsManager = (CarUxRestrictionsManager) + car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE); + parseActiveUxRestriction(mCarUxRestrictionsManager.getCurrentCarUxRestrictions().getActiveRestrictions()); + uxRestrictionStatusColdStream.onNext(new CarUxRestrictionStatus(mIsRequiresDistractionOptimization, mCarUxRestriction)); + } + } + + @Override + public CarUxRestriction getActiveCarUxRestriction() { + return mCarUxRestriction; + } + + @Override + public Observable observeCarUxRestrictionChanged() { + return uxRestrictionStatusColdStream; + } + + @Override + public void registerListener() { + Log.d(TAG, "Register UX restrictions listener."); + CarUxRestrictionsManager.OnUxRestrictionsChangedListener uxrChangeListener = + new CarUxRestrictionsManager.OnUxRestrictionsChangedListener() { + @Override + public void onUxRestrictionsChanged(CarUxRestrictions carUxRestrictions) { + Log.d(TAG, "onUxRestrictionsChanged"); + mIsRequiresDistractionOptimization = carUxRestrictions.isRequiresDistractionOptimization(); + parseActiveUxRestriction(carUxRestrictions.getActiveRestrictions()); + uxRestrictionStatusColdStream.onNext(new CarUxRestrictionStatus(mIsRequiresDistractionOptimization, mCarUxRestriction)); + } + }; + mCarUxRestrictionsManager.registerListener(uxrChangeListener); + uxrChangeListener.onUxRestrictionsChanged(mCarUxRestrictionsManager.getCurrentCarUxRestrictions()); + } + + @Override + public void unregisterListener() { + Log.d(TAG, "Unregister UX restrictions listener."); + mCarUxRestrictionsManager.unregisterListener(); + } + + /** + * Parse active restriction code to a CarUxRestriction object. + * @param activeRestriction active restriction code. + */ + private void parseActiveUxRestriction(int activeRestriction) { + switch (activeRestriction) { + case UX_RESTRICTIONS_FULLY_RESTRICTED_CODE: + mCarUxRestriction = new CarUxRestriction(UX_RESTRICTIONS_FULLY_RESTRICTED_NAME); + mIsRequiresDistractionOptimization = true; + break; + case UX_RESTRICTIONS_NO_RESTRICTION_CODE: + mCarUxRestriction = new CarUxRestriction(UX_RESTRICTIONS_NO_RESTRICTION_NAME); + mIsRequiresDistractionOptimization = false; + break; + default: + Log.w(TAG,"Fail to recognize active ux restriction code."); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/res/values/strings.xml new file mode 100644 index 000000000..c81954a73 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-ux-restrictions/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Alexa Auto UX Restrictions + \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/.gitignore b/aacs/android/app-components/alexa-auto-voice-interaction/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/.gitignore rename to aacs/android/app-components/alexa-auto-voice-interaction/.gitignore diff --git a/aacs/android/app-components/alexa-auto-voice-interaction/README.md b/aacs/android/app-components/alexa-auto-voice-interaction/README.md new file mode 100644 index 000000000..e4e936763 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-interaction/README.md @@ -0,0 +1,10 @@ +# Alexa Auto Voice Interaction + +The following list describes the purposes of this library: +* It provides the Alexa Voice Interaction Service (VIS), which extends the Android Voice Interaction Service API. Alexa VIS enables Alexa as a voice assistant on an Android device. To start Alexa VIS, the user goes to `Settings > Apps & notifications > Default apps > Assist & voice input`, and selects Alexa. + >**Note:** After Alexa VIS is integrated with the Android Voice Interaction API, infotainment system only supports one voice agent at a time. For example, the user cannot use both Alexa and Google Voice Assistant at the same time. +* It is responsible for managing the Alexa Auto Client Service (AACS) lifecycle, based on the Alexa VIS lifecycle. +* When there is new voice session created, it starts an assistant activity displayed on top of other activities in the system. +* It provides the Alexa Voice Assist Settings, such as Alexa Privacy Mode and Alexa Locale. To open Alexa Voice Assist Settings, the user goes to `Settings > Apps & notifications > Default apps > Assist & voice input`, makes sure Alexa is selected, and clicks the Settings icon beside `Assist app` to open the Alexa Voice Assist Settings homepage. + +When the user selects Alexa as the assistant, AACS is started and connected to Alexa. When the user selects another voice assistant, Alexa VIS shuts down. It also stops AACS. \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-voice-interaction/build.gradle b/aacs/android/app-components/alexa-auto-voice-interaction/build.gradle new file mode 100644 index 000000000..984ba99c9 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-interaction/build.gradle @@ -0,0 +1,72 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-voice-interaction" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } +} + + +dependencies { + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':aacscommonutils') + implementation project(':alexa-auto-apis') + implementation project(':alexa-auto-apps-common-util') + implementation project(':alexa-auto-apps-common-ui') + implementation project(':alexa-auto-settings') + implementation project(':alexa-auto-voice-ui') + + // AndroidX dependencies + implementation deps.androidx_annotation + implementation deps.androidx_appcompat + implementation deps.androidx_core + + // RX + implementation deps.rxjava3 + + // Eventbus + implementation deps.eventbus + + // Test Dependencies + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.roboelectric +} diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/gradle.properties b/aacs/android/app-components/alexa-auto-voice-interaction/gradle.properties similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/gradle.properties rename to aacs/android/app-components/alexa-auto-voice-interaction/gradle.properties diff --git a/platforms/android/app-components/alexa-auto-telephony/aacstelephony/proguard-rules.pro b/aacs/android/app-components/alexa-auto-voice-interaction/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/aacstelephony/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-voice-interaction/proguard-rules.pro diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/AndroidManifest.xml rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/AndroidManifest.xml diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/AutoVoiceInteractionMessage.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/AutoVoiceInteractionMessage.java similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/AutoVoiceInteractionMessage.java rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/AutoVoiceInteractionMessage.java diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/Constants.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/Constants.java similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/Constants.java rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/common/Constants.java diff --git a/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiver.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiver.java new file mode 100644 index 000000000..017429a06 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiver.java @@ -0,0 +1,74 @@ +package com.amazon.alexa.auto.voiceinteraction.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; +import com.amazon.alexa.auto.aacs.common.ConnectionStatusChangedMessages; +import com.amazon.alexa.auto.aacs.common.WakewordDetectedMessages; +import com.amazon.alexa.auto.voiceinteraction.common.AutoVoiceInteractionMessage; +import com.amazon.alexa.auto.voiceinteraction.common.Constants; + +import org.greenrobot.eventbus.EventBus; + +public class AACSBroadcastReceiver extends BroadcastReceiver { + private static final String TAG = AACSBroadcastReceiver.class.getCanonicalName(); + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceived"); + if (intent == null || intent.getAction() == null) { + return; + } + + AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { + Log.d(TAG, message.messageId + " | " + message.topic + " | " + message.action + " | " + message.payload); + + switch (message.action) { + case Action.AlexaClient.CONNECTION_STATUS_CHANGED: + handleConnectionStatusChanged(message); + break; + case Action.SpeechRecognizer.WAKEWORD_DETECTED: + handleWakewordDetected(message); + break; + case Action.SpeechRecognizer.END_OF_SPEECH_DETECTED: + sendAutoVoiceInteractionMessage( + Topic.SPEECH_RECOGNIZER, Action.SpeechRecognizer.END_OF_SPEECH_DETECTED, ""); + break; + } + }); + } + + @VisibleForTesting + void handleConnectionStatusChanged(@NonNull AACSMessage aacsMessage) { + if (aacsMessage.payload != null) { + ConnectionStatusChangedMessages.parseConnectionStatus(aacsMessage.payload).ifPresent(message -> { + sendAutoVoiceInteractionMessage(Constants.TOPIC_ALEXA_CONNECTION, message, ""); + }); + } + } + + @VisibleForTesting + void handleWakewordDetected(@NonNull AACSMessage aacsMessage) { + if (aacsMessage.payload != null) { + WakewordDetectedMessages.parseWakeword(aacsMessage.payload).ifPresent(payload -> { + sendAutoVoiceInteractionMessage( + Constants.TOPIC_VOICE_ANIMATION, Action.SpeechRecognizer.WAKEWORD_DETECTED, payload); + }); + } + } + + @VisibleForTesting + void sendAutoVoiceInteractionMessage(String topic, String action, String payload) { + Log.d(TAG, "Sending Alexa Auto voice interaction message, topic: " + topic + ", action: " + action); + EventBus.getDefault().post(new AutoVoiceInteractionMessage(topic, action, payload)); + } +} diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java similarity index 85% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java index a91f754ae..4d988c0f5 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java +++ b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionService.java @@ -1,7 +1,6 @@ package com.amazon.alexa.auto.voiceinteraction.service; import android.content.Context; -import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; @@ -12,15 +11,18 @@ import com.amazon.aacsconstants.Action; import com.amazon.aacsconstants.Topic; import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; import com.amazon.alexa.auto.apis.app.AlexaApp; import com.amazon.alexa.auto.apis.auth.AuthController; import com.amazon.alexa.auto.apis.module.ModuleInterface; import com.amazon.alexa.auto.apps.common.aacs.AACSServiceController; +import com.amazon.alexa.auto.apps.common.util.UiThemeManager; import com.amazon.alexa.auto.settings.config.AACSConfigurationPreferences; import com.amazon.alexa.auto.settings.config.AACSConfigurator; import com.amazon.alexa.auto.voiceinteraction.common.AutoVoiceInteractionMessage; import com.amazon.alexa.auto.voiceinteraction.common.Constants; -import com.amazon.alexa.auto.voiceinteraction.session.SessionViewControllerImpl; +import com.amazon.alexa.auto.voice.ui.session.SessionActivityControllerImpl; +import com.amazon.alexa.auto.voice.ui.session.SessionViewControllerImpl; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -46,6 +48,9 @@ public class AutoVoiceInteractionService extends VoiceInteractionService { AuthController mAuthController; AACSConfigurator mAACSConfigurator; + UiThemeManager mUiThemeManager; + AACSSender mAACSSender; + AACSMessageSender mMessageSender; private ExecutorService mExecutorService; private Handler mMainThreadHandler; @@ -65,6 +70,7 @@ public void onCreate() { AlexaApp mApp = AlexaApp.from(this); mApp.getRootComponent().activateScope(new SessionViewControllerImpl()); + mApp.getRootComponent().activateScope(new SessionActivityControllerImpl()); // Initializing extra modules getModuleAsync().filter(Optional::isPresent).map(Optional::get).subscribe((modules) -> { @@ -74,10 +80,13 @@ public void onCreate() { }); mAuthController = mApp.getRootComponent().getAuthController(); + mAACSSender = new AACSSender(); WeakReference ContextWk = new WeakReference<>(this.getApplicationContext()); mAACSConfigurator = - new AACSConfigurator(ContextWk, new AACSSender(), new AACSConfigurationPreferences(ContextWk)); + new AACSConfigurator(ContextWk, mAACSSender, new AACSConfigurationPreferences(ContextWk)); + mMessageSender = new AACSMessageSender(ContextWk, mAACSSender); + mUiThemeManager = new UiThemeManager(getApplicationContext(), mMessageSender); } @Override @@ -95,19 +104,24 @@ public void onReady() { if (ms_since_device_bootup < device_boot_margin_ms) { Log.d(TAG, "Will start AACS after 30 seconds. Milliseconds since device bootup " + ms_since_device_bootup); new Handler().postDelayed(() -> { - mAACSConfigurator.shareFilesWithAACS(this.getApplicationContext()); + Log.d(TAG, "Starting AACS after delay. Milliseconds since device bootup " + ms_since_device_bootup); AACSServiceController.startAACS(this, true); }, aacs_start_delay_ms); } else { - Log.d(TAG, "Starting AACS. Milliseconds since device bootup " + ms_since_device_bootup); - mAACSConfigurator.shareFilesWithAACS(this.getApplicationContext()); + Log.d(TAG, "Starting AACS right away. Milliseconds since device bootup " + ms_since_device_bootup); AACSServiceController.startAACS(this, true); } + + // The order is important! Share files before configuring AACS. + mAACSConfigurator.shareFilesWithAACS(this.getApplicationContext()); + // Configure AACS immediately without waiting for delay start to avoid consistent ANRs in AACS. mAACSConfigurator.configureAACSWithPreferenceOverrides(); if (mAuthController.isAuthenticated()) { isAlexaConnected = true; } + + mUiThemeManager.init(); } @Override @@ -123,6 +137,8 @@ public void onShutdown() { moduleInterface.uninitialize(this.getApplicationContext()); } }); + + mUiThemeManager.destroy(); } @Subscribe diff --git a/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSession.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSession.java new file mode 100644 index 000000000..841b836af --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSession.java @@ -0,0 +1,51 @@ +package com.amazon.alexa.auto.voiceinteraction.service; + +import android.app.assist.AssistContent; +import android.app.assist.AssistStructure; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.service.voice.VoiceInteractionSession; +import android.util.Log; + +import com.amazon.alexa.auto.voice.ui.VoiceActivity; + +import androidx.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +/** + * Active Alexa Auto voice interaction session, providing a facility for starting a new assistant activity + * displayed on top of other activities in the system. + */ +public class AutoVoiceInteractionSession extends VoiceInteractionSession { + private static final String TAG = AutoVoiceInteractionSession.class.getCanonicalName(); + + public AutoVoiceInteractionSession(@NotNull Context context) { + super(context); + } + + @Override + public void onShow(Bundle args, int showFlags) { + Log.d(TAG, "onShow"); + super.onShow(args, showFlags); + + Intent intent = new Intent(getContext(), VoiceActivity.class); + intent.putExtras(args); + startAssistantActivity(intent); + } + + @Override + public void onPrepareShow(Bundle args, int showFlags) { + Log.d(TAG, "onPrepareShow"); + super.onPrepareShow(args, showFlags); + setUiEnabled(false); + } + + @Override + public void onHandleAssist( + @Nullable Bundle data, @Nullable AssistStructure structure, @Nullable AssistContent content) { + Log.d(TAG, "onHandleAssist"); + super.onHandleAssist(data, structure, content); + } +} \ No newline at end of file diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSessionService.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSessionService.java similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSessionService.java rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/service/AutoVoiceInteractionSessionService.java diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/res/values/strings.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values/strings.xml rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/res/values/strings.xml diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/xml/auto_voice_interaction_service.xml b/aacs/android/app-components/alexa-auto-voice-interaction/src/main/res/xml/auto_voice_interaction_service.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/xml/auto_voice_interaction_service.xml rename to aacs/android/app-components/alexa-auto-voice-interaction/src/main/res/xml/auto_voice_interaction_service.xml diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/TestResourceFileReader.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/TestResourceFileReader.java similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/TestResourceFileReader.java rename to aacs/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/TestResourceFileReader.java diff --git a/aacs/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiverTest.java b/aacs/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiverTest.java new file mode 100644 index 000000000..fd24dcba8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/receiver/AACSBroadcastReceiverTest.java @@ -0,0 +1,106 @@ +package com.amazon.alexa.auto.voiceinteraction.receiver; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.amazon.aacsconstants.AASBConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.alexa.auto.voiceinteraction.TestResourceFileReader; +import com.amazon.alexa.auto.voiceinteraction.common.AutoVoiceInteractionMessage; +import com.amazon.alexa.auto.voiceinteraction.common.Constants; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.Optional; + +@RunWith(RobolectricTestRunner.class) +public class AACSBroadcastReceiverTest { + @Mock + private Context context; + + private AACSBroadcastReceiver aacsBroadcastReceiver; + private EventBus eventBus; + private Intent mIntent; + + private String receiveMessageTopic; + private String receiveMessageAction; + private String receiveMessagePayload; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + aacsBroadcastReceiver = spy(new AACSBroadcastReceiver()); + EventBus.getDefault().register(this); + eventBus = spy(EventBus.getDefault()); + } + + @Test + public void handle_aacs_connection_status_connected_intent() { + generateIntent("aacs/ConnectionStatusChangedConnected.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceInteractionMessage( + Constants.TOPIC_ALEXA_CONNECTION, Constants.CONNECTION_STATUS_CONNECTED, ""); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_ALEXA_CONNECTION); + Assert.assertEquals(receiveMessageAction, Constants.CONNECTION_STATUS_CONNECTED); + } + + @Test + public void handle_aacs_connection_status_disconnected_intent() { + generateIntent("aacs/ConnectionStatusChangedDisconnected.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceInteractionMessage( + Constants.TOPIC_ALEXA_CONNECTION, Constants.CONNECTION_STATUS_DISCONNECTED, ""); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_ALEXA_CONNECTION); + Assert.assertEquals(receiveMessageAction, Constants.CONNECTION_STATUS_DISCONNECTED); + } + + @Test + public void handle_aacs_wakeword_detected_intent() { + generateIntent("aacs/WakewordDetected.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceInteractionMessage(Constants.TOPIC_VOICE_ANIMATION, + Action.SpeechRecognizer.WAKEWORD_DETECTED, "wakeword-SampleText"); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_VOICE_ANIMATION); + Assert.assertEquals(receiveMessageAction, Action.SpeechRecognizer.WAKEWORD_DETECTED); + Assert.assertEquals(receiveMessagePayload, "wakeword-SampleText"); + } + + @Test + public void ignore_invalid_intent_action() { + mIntent = new Intent(""); + verify(aacsBroadcastReceiver, times(0)).handleConnectionStatusChanged(any()); + verify(aacsBroadcastReceiver, times(0)).sendAutoVoiceInteractionMessage(any(), any(), any()); + } + + private void generateIntent(String resPath) { + mIntent = new Intent(Constants.DIALOG_STATE_CHANGE); + Optional sampleAACSListeningMessage = TestResourceFileReader.readFileContent(resPath); + Bundle sampleListeningPayload = new Bundle(); + sampleListeningPayload.putString("message", sampleAACSListeningMessage.get()); + mIntent.putExtra("payload", sampleListeningPayload); + } + + @Subscribe + public void testOnReceiveEvent(AutoVoiceInteractionMessage message) { + receiveMessageTopic = message.getTopic(); + receiveMessageAction = message.getAction(); + receiveMessagePayload = message.getPayload(); + } +} diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedConnected.json b/aacs/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedConnected.json similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedConnected.json rename to aacs/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedConnected.json diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedDisconnected.json b/aacs/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedDisconnected.json similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedDisconnected.json rename to aacs/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/ConnectionStatusChangedDisconnected.json diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/WakewordDetected.json b/aacs/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/WakewordDetected.json similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/WakewordDetected.json rename to aacs/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/WakewordDetected.json diff --git a/aacs/android/app-components/alexa-auto-voice-ui/.gitignore b/aacs/android/app-components/alexa-auto-voice-ui/.gitignore new file mode 100644 index 000000000..4ee3b0cfe --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/.gitignore @@ -0,0 +1,9 @@ +.gradle/ +.idea/ +build/ +gradle/ +libs/ +gradlew +gradlew.bat +local.properties +.DS_Store diff --git a/aacs/android/app-components/alexa-auto-voice-ui/README.md b/aacs/android/app-components/alexa-auto-voice-ui/README.md new file mode 100644 index 000000000..f20fff05e --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/README.md @@ -0,0 +1,11 @@ +# Alexa Auto Voice UI + +The following list describes the purposes of this library: +* It handles Alexa Voice Chrome UI based on the user's request. Voice Chrome requires that Alexa be selected as the device's voice assistant. +* It provides the voice interaction session view and vends it out to the app components that inflate onto that view. To access the VIS component, consumers need to get the `SessionViewController` object via `alexa-auto-apis`. (See the example in `alexa-auto-navigation` : [LocalSearchDirectiveHandler](../alexa-auto-navigation/src/main/java/com/amazon/alexa/auto/navigation/handlers/LocalSearchDirectiveHandler.java).) +* It provides the voice interaction session activity and vends it out to the app components that add voice fragment onto that view. Consumers need to get the `SessionActivityController` object via `alexa-auto-apis`. (See the example in `alexa-auto-apl-renderer` : [APLReceiver](../alexa-auto-apl-renderer/src/main/java/com/amazon/alexa/auto/apl/receiver/APLReceiver.java).) +* It provides support for offline network error prompts. With this feature, an offline prompt is played to users when Alexa is unable to respond to utterances in case the internet is not reachable. The prompt is played in the currently active system locale and the error prompt files for the different locales are stored in `res/raw/auto_error_offline_{locale}.mp3` + +## Known Issues + +* This only applies to Alexa Custom Assistant - If Alexa is disabled, [Brandon] is enabled and network is unavailable, the voice prompt will be played in Alexa's voice, not in [Brandon]'s. \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-voice-ui/build.gradle b/aacs/android/app-components/alexa-auto-voice-ui/build.gradle new file mode 100644 index 000000000..54b12e801 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/build.gradle @@ -0,0 +1,73 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + defaultConfig { + minSdkVersion 26 + targetSdkVersion 28 + versionCode 1 + versionName "4.0" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + debug { + testCoverageEnabled true + debuggable true + } + } + + testOptions { + // Unit Test: Make all android methods return true by default + unitTests.returnDefaultValues = true + } + + compileOptions { + targetCompatibility 1.8 + sourceCompatibility 1.8 + } + + libraryVariants.all { variant -> + variant.outputs.all { + def project = "alexa-auto-voice-ui" + def separator = "_" + def buildType = variant.buildType.name + def apkName = project + separator + buildType + ".aar" + outputFileName = new File(apkName) + } + } +} + + +dependencies { + // Pre-Built. + implementation(name:'autovoicechrome', ext:'aar') + + implementation project(':aacsconstants') + implementation project(':aacsipc') + implementation project(':aacscommonutils') + implementation project(':alexa-auto-apis') + implementation project(':alexa-auto-apps-common-util') + implementation project(':alexa-auto-apps-common-ui') + + // AndroidX dependencies + implementation deps.androidx_annotation + implementation deps.androidx_appcompat + implementation deps.androidx_core + + // RX + implementation deps.rxjava3 + + // Eventbus + implementation deps.eventbus + + // Test Dependencies + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.roboelectric +} diff --git a/samples/android-aacs-sample-app/gradle.properties b/aacs/android/app-components/alexa-auto-voice-ui/gradle.properties similarity index 100% rename from samples/android-aacs-sample-app/gradle.properties rename to aacs/android/app-components/alexa-auto-voice-ui/gradle.properties diff --git a/platforms/android/app-components/alexa-auto-templateruntime-renderer/proguard-rules.pro b/aacs/android/app-components/alexa-auto-voice-ui/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-templateruntime-renderer/proguard-rules.pro rename to aacs/android/app-components/alexa-auto-voice-ui/proguard-rules.pro diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/AndroidManifest.xml b/aacs/android/app-components/alexa-auto-voice-ui/src/main/AndroidManifest.xml new file mode 100644 index 000000000..a4969a527 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/VoiceActivity.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/VoiceActivity.java new file mode 100644 index 000000000..3d5b8265e --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/VoiceActivity.java @@ -0,0 +1,426 @@ +package com.amazon.alexa.auto.voice.ui; + +import android.graphics.Color; +import android.media.MediaPlayer; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import com.amazon.aacsconstants.AASBConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.aacsipc.AACSSender; +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; +import com.amazon.alexa.auto.aacs.common.AACSMessageSender; +import com.amazon.alexa.auto.aacs.common.SpeechRecognizerMessages; +import com.amazon.alexa.auto.apis.alexaCustomAssistant.AnimationProvider; +import com.amazon.alexa.auto.apis.alexaCustomAssistant.EarconProvider; +import com.amazon.alexa.auto.apis.app.AlexaApp; +import com.amazon.alexa.auto.apis.app.AlexaAppRootComponent; +import com.amazon.alexa.auto.apis.session.SessionActivityController; +import com.amazon.alexa.auto.apis.session.SessionViewController; +import com.amazon.alexa.auto.apps.common.util.ModuleProvider; +import com.amazon.alexa.auto.apps.common.util.NetworkUtil; +import com.amazon.alexa.auto.voice.ui.common.AutoVoiceUIMessage; +import com.amazon.alexa.auto.voice.ui.common.Constants; +import com.amazon.alexa.auto.voice.ui.earcon.EarconController; +import com.amazon.autovoicechrome.AutoVoiceChromeController; +import com.amazon.autovoicechrome.util.AutoVoiceChromeState; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; + +import java.lang.ref.WeakReference; +import java.util.Optional; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AppCompatActivity; +import androidx.fragment.app.Fragment; +import io.reactivex.rxjava3.disposables.Disposable; + +import static com.amazon.alexa.auto.apps.common.util.ModuleProvider.ModuleName.LVC; +import static com.amazon.alexa.auto.apps.common.util.NetworkUtil.TYPE_NOT_CONNECTED; + +/** + * Active Alexa Auto voice session activity, providing a facility for the implementation + * to interact with the user in the voice interaction layer, such as showing voice chrome animation, + * inflating voice fragment based on the capability. + */ +public class VoiceActivity extends AppCompatActivity { + private static final String TAG = VoiceActivity.class.getCanonicalName(); + + private Disposable mActivityControllerDisposable; + private boolean mVoiceSessionInUse; + private boolean mSessionEnded; + private Disposable mViewControllerDisposable; + private MediaPlayer mNetworkErrorTTSPrompt; + private Fragment mVoiceFragment; + + @NonNull + AutoVoiceChromeController mAutoVoiceChromeController; + @NonNull + EarconController mEarconController; + @NonNull + SpeechRecognizerMessages mSpeechRecognizerMessages; + @NonNull + private AACSSender mAACSSender; + @NonNull + private AACSMessageSender mMessageSender; + + @VisibleForTesting + View mContentView; + + AnimationProvider mAnimationProvider; + EarconProvider mEarconProvider; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setTheme(R.style.Theme_Alexa_VoiceInteractionUi_Activity); + setContentView(R.layout.autovoiceinteraction_layout); + + mAutoVoiceChromeController = new AutoVoiceChromeController(getApplicationContext()); + mEarconController = new EarconController(getApplicationContext()); + mAACSSender = new AACSSender(); + mMessageSender = new AACSMessageSender(new WeakReference<>(getApplicationContext()), mAACSSender); + mSpeechRecognizerMessages = new SpeechRecognizerMessages(mMessageSender); + + EventBus.getDefault().register(this); + mEarconController.initEarcon(); + mNetworkErrorTTSPrompt = MediaPlayer.create(getApplicationContext(), R.raw.auto_error_offline); + initializeProviders(); + + // Getting voice chrome view group for auto voice chrome controller + mContentView = findViewById(R.id.auto_voice_interaction_view_container); + + ViewGroup v = (ViewGroup) mContentView; + + // Getting voice chrome view group for auto voice chrome controller + ViewGroup autoVoiceChromeBarView = (ViewGroup) v.getChildAt(1); + + mAutoVoiceChromeController.initialize(autoVoiceChromeBarView); + + // Initializing animation provider if it exists + if (mAnimationProvider != null) { + // Inflate custom animation layout onto the root view + getLayoutInflater().inflate(mAnimationProvider.getCustomLayout(), v); + ViewGroup autoCustomAnimationView = (ViewGroup) v.getChildAt(2); + mAnimationProvider.initialize(getApplicationContext(), autoCustomAnimationView); + } + + // TODO: we provide user a way to cancel Alexa voice request anytime needed, now it can be anywhere on the + // screen, the UX could be replace with "X" button, need UX confirm + mContentView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.d(TAG, "Cancel current Alexa request"); + AACSMessageBuilder.buildMessage(Topic.ALEXA_CLIENT, Action.AlexaClient.STOP_FOREGROUND_ACTIVITY, "") + .ifPresent(message -> { + mMessageSender.sendMessage( + Topic.ALEXA_CLIENT, Action.AlexaClient.STOP_FOREGROUND_ACTIVITY, ""); + }); + AlexaApp app = AlexaApp.from(getApplicationContext()); + Optional viewController = + app.getRootComponent().getComponent(SessionViewController.class); + viewController.ifPresent(SessionViewController::clearTemplate); + finish(); + } + }); + + Bundle args = getIntent().getExtras(); + + if (args.containsKey(Topic.SPEECH_RECOGNIZER)) { + String action = args.getString(Topic.SPEECH_RECOGNIZER); + if (mEarconProvider != null) { + if (Action.SpeechRecognizer.WAKEWORD_DETECTED.equals(action)) { + mEarconController.playAudioCueStartVoice( + mEarconProvider.shouldUseAudioCueStartVoice(args.getString(action))); + } + } else { + if (Action.SpeechRecognizer.WAKEWORD_DETECTED.equals(action)) { + mEarconController.playAudioCueStartVoice(); + } + } + + if (mAnimationProvider != null) { + switchAnimation(AutoVoiceChromeState.LISTENING.toString()); + } else { + mAutoVoiceChromeController.onStateChanged(AutoVoiceChromeState.LISTENING); + } + } else if (args.containsKey(Constants.TOPIC_ALEXA_CONNECTION)) { + if (Constants.ACTION_ALEXA_NOT_CONNECTED.equals(args.getString(Constants.TOPIC_ALEXA_CONNECTION))) { + //Error chrome is only shown if authenticated + if (AlexaApp.from(getApplicationContext()).getRootComponent().getAuthController().isAuthenticated()) { + mAutoVoiceChromeController.onStateChanged(AutoVoiceChromeState.IN_ERROR); + mNetworkErrorTTSPrompt.start(); + } + + } + } else { + // User presses PTT + if (AlexaApp.from(getApplicationContext()).getRootComponent().getAuthController().isAuthenticated()) { + int connectivityStatus = NetworkUtil.getConnectivityStatus(getApplicationContext()); + if ( connectivityStatus == NetworkUtil.TYPE_NOT_CONNECTED + && !ModuleProvider.containsModule(getApplicationContext(), LVC)) { + mAutoVoiceChromeController.onStateChanged(AutoVoiceChromeState.IN_ERROR); + mNetworkErrorTTSPrompt.start(); + } else { + //Notifying AACS to start capture + Log.d(TAG, "PTT: Start capture..."); + mSpeechRecognizerMessages.sendStartCapture(AASBConstants.SpeechRecognizer.SPEECH_INITIATOR_TAP_TO_TALK); + mEarconController.playAudioCueStartTouch(); + + if (mAnimationProvider != null) { + // Prepare animation for PTT action + mAnimationProvider.prepareAnimationForPTT(); + switchAnimation(AutoVoiceChromeState.LISTENING.toString()); + } else { + mAutoVoiceChromeController.onStateChanged(AutoVoiceChromeState.LISTENING); + } + } + } else { + Log.d(TAG, "PTT: User not authenticated, ignoring ..."); + } + } + + setVISViewForSessionController(); + } + + public void onStart() { + Log.d(TAG, "onStart"); + super.onStart(); + + if (!isFinishing()) { + // Clear previous added fragment if voice session is not in used + if (!mVoiceSessionInUse) { + AlexaApp.from(getApplicationContext()) + .getRootComponent() + .getComponent(SessionActivityController.class) + .ifPresent(SessionActivityController::removeFragment); + } + + // Subscribe fragment added observable to add/remove fragment in voice activity + AlexaApp app = AlexaApp.from(getApplicationContext()); + Optional viewController = + app.getRootComponent().getComponent(SessionActivityController.class); + viewController.ifPresent(sessionActivityController -> { + mActivityControllerDisposable = + sessionActivityController.getFragmentAddedObservable().subscribe(fragmentAdded -> { + Log.d(TAG, "ActivityControllerDisposable | fragmentAdded | " + fragmentAdded); + mVoiceSessionInUse = fragmentAdded; + + mVoiceFragment = sessionActivityController.getFragment(); + if (mVoiceFragment != null) { + if (fragmentAdded) { + getSupportFragmentManager().beginTransaction().add(R.id.auto_voice_interaction_view_container, + mVoiceFragment, mVoiceFragment.getClass().getSimpleName()).commit(); + + } else { + getSupportFragmentManager().beginTransaction().remove(mVoiceFragment).commit(); + mVoiceFragment = null; + + if (mSessionEnded) { + Log.d(TAG, + "FragmentAddedObservable | fragment removed and session is " + + "finished so finishing activity"); + finish(); + } + } + } + }); + }); + } + } + + @Override + public void onStop() { + Log.d(TAG, "onStop"); + super.onStop(); + + mVoiceSessionInUse = false; + finish(); + } + + @Override + public void finish() { + Log.d(TAG, "finish"); + super.finish(); + + // Clean up visuals and eventbus in finish() callback instead of onDestroy() to prevent + // leaking IntentReceiver and crashing the app when session is finished. + mAutoVoiceChromeController.onDestroy(); + if (mAnimationProvider != null) { + mAnimationProvider.uninitialize(); + } + EventBus.getDefault().unregister(this); + } + + @Override + public void onDestroy() { + Log.d(TAG, "onDestroy"); + super.onDestroy(); + mEarconController.uninitEarcon(); + if (mNetworkErrorTTSPrompt != null) { + mNetworkErrorTTSPrompt.release(); + mNetworkErrorTTSPrompt = null; + } + + uninitializeProviders(); + + AlexaApp.from(getApplicationContext()) + .getRootComponent() + .getComponent(SessionViewController.class) + .ifPresent(sessionViewController -> sessionViewController.setSessionView(null)); + if (mViewControllerDisposable != null) { + mViewControllerDisposable.dispose(); + mViewControllerDisposable = null; + } + if (mActivityControllerDisposable != null) { + mActivityControllerDisposable.dispose(); + mActivityControllerDisposable = null; + } + } + + @Subscribe + public void onVoiceUiStateChange(AutoVoiceUIMessage message) { + Log.d(TAG, + "Receiving voice interaction message, topic: " + message.getTopic() + + " action: " + message.getAction()); + + if (!isFinishing()) { + if (message.getTopic().equals(Constants.TOPIC_VOICE_ANIMATION)) { + switch (message.getAction()) { + case Action.AlexaClient.DIALOG_STATE_CHANGED: + if (mAnimationProvider != null) { + // Switching animation for dialog state changed + switchAnimation(message.getPayload()); + } else { + mAutoVoiceChromeController.onStateChanged( + convertToAutoVoiceChromeDialogState(message.getPayload())); + } + + if (message.getPayload().equals(AutoVoiceChromeState.IDLE.toString())) { + mSessionEnded = true; + if (!mVoiceSessionInUse) { + Log.d(TAG, "voice session idle, so finishing voice session."); + finish(); + } + } else if (message.getPayload().equals(AutoVoiceChromeState.LISTENING.toString())) { + mSessionEnded = false; + } + break; + case Action.Animation.ANIMATION_SWITCH: + if (mAnimationProvider != null) { + switchAnimation(AutoVoiceChromeState.SPEAKING.toString()); + } + } + } else if (message.getAction().equals(Action.SpeechRecognizer.END_OF_SPEECH_DETECTED)) { + if (mEarconProvider != null) { + mEarconController.playAudioCueEnd(mEarconProvider.shouldUseAudioCueEnd("")); + } else { + mEarconController.playAudioCueEnd(); + } + } + } + } + + private void initializeProviders() { + if (getApplicationContext() != null) { + AlexaApp app = AlexaApp.from(getApplicationContext()); + AlexaAppRootComponent alexaAppRootComponent = app.getRootComponent(); + if (alexaAppRootComponent != null + && alexaAppRootComponent.getComponent(AnimationProvider.class).isPresent()) { + mAnimationProvider = alexaAppRootComponent.getComponent(AnimationProvider.class).get(); + } + if (alexaAppRootComponent != null && alexaAppRootComponent.getComponent(EarconProvider.class).isPresent()) { + mEarconProvider = alexaAppRootComponent.getComponent(EarconProvider.class).get(); + } + } + } + + private void uninitializeProviders() { + if (mAnimationProvider != null) { + mAnimationProvider = null; + } + + if (mEarconProvider != null) { + mEarconProvider = null; + } + } + + private void switchAnimation(String dialogState) { + if (mAnimationProvider.shouldTakeOver()) { + // Clear alexa chrome before switching to custom animation provider + mAutoVoiceChromeController.onStateChanged(AutoVoiceChromeState.IDLE); + mAnimationProvider.doTakeOver(dialogState); + } else { + // Clear custom animation provider before switching to alexa chrome + mAnimationProvider.doTakeOver(AutoVoiceChromeState.IDLE.toString()); + mAutoVoiceChromeController.onStateChanged(convertToAutoVoiceChromeDialogState(dialogState)); + } + } + + /** + * Set VIS view for session controller. This view will be used by other components to inflate + * visual elements onto. + */ + private void setVISViewForSessionController() { + ViewGroup view = findViewById(R.id.auto_voice_interaction_view); + + AlexaApp app = AlexaApp.from(getApplicationContext()); + Optional viewController = + app.getRootComponent().getComponent(SessionViewController.class); + + viewController.ifPresent(sessionViewController -> { + sessionViewController.setSessionView(view); + mViewControllerDisposable = + sessionViewController.getTemplateDisplayedObservable().subscribe(templateDisplayed -> { + Log.d(TAG, "TemplateDisplayedObservable | templateDisplayed | " + templateDisplayed); + mVoiceSessionInUse = templateDisplayed; + + View layout = findViewById(R.id.auto_voice_chrome_bar_view); + if (templateDisplayed) { + layout.setBackgroundColor(getApplicationContext().getResources().getColor(R.color.transparent_black)); + } else { + layout.setBackgroundColor(Color.TRANSPARENT); + } + + if (!templateDisplayed && mSessionEnded) { + Log.d(TAG, + "TemplateDisplayedObservable | template cleared and session is " + + "finished so finishing activity"); + finish(); + } + }); + }); + } + + /** + * Convert AlexaClient Dialog state to AutoVoiceChrome dialog state + * + * @param state DialogState + * @return AutoVoiceChromeState + */ + @VisibleForTesting + AutoVoiceChromeState convertToAutoVoiceChromeDialogState(String state) { + AutoVoiceChromeState autoVoiceChromeState = AutoVoiceChromeState.UNKNOWN; + switch (state) { + case "IDLE": + case "EXPECTING": + autoVoiceChromeState = AutoVoiceChromeState.IDLE; + break; + case "SPEAKING": + autoVoiceChromeState = AutoVoiceChromeState.SPEAKING; + break; + case "THINKING": + autoVoiceChromeState = AutoVoiceChromeState.THINKING; + break; + case "LISTENING": + autoVoiceChromeState = AutoVoiceChromeState.LISTENING; + break; + } + return autoVoiceChromeState; + } +} \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/AutoVoiceUIMessage.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/AutoVoiceUIMessage.java new file mode 100644 index 000000000..848f334af --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/AutoVoiceUIMessage.java @@ -0,0 +1,30 @@ +package com.amazon.alexa.auto.voice.ui.common; + +import androidx.annotation.Nullable; + +/** + * Alexa Auto Voice UI Message + */ +public class AutoVoiceUIMessage { + private String topic; + private String action; + private String payload; + + public AutoVoiceUIMessage(String topic, String action, @Nullable String payload) { + this.topic = topic; + this.action = action; + this.payload = payload; + } + + public String getTopic() { + return this.topic; + } + + public String getAction() { + return this.action; + } + + public String getPayload() { + return this.payload; + } +} diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/Constants.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/Constants.java new file mode 100644 index 000000000..e22084904 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/common/Constants.java @@ -0,0 +1,13 @@ +package com.amazon.alexa.auto.voice.ui.common; + +public class Constants { + // Voice UI Topic + public static final String TOPIC_VOICE_ANIMATION = "VOICE_ANIMATION"; + public static final String TOPIC_ALEXA_CONNECTION = "ALEXA_CONNECTION"; + + // Voice UI Action + public static final String ACTION_ALEXA_NOT_CONNECTED = "ALEXA_NOT_CONNECTED"; + + // AACS intents + public static final String DIALOG_STATE_CHANGE = "com.amazon.aacs.aasb.DialogStateChanged"; +} diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/earcon/EarconController.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/earcon/EarconController.java new file mode 100644 index 000000000..ae482c066 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/earcon/EarconController.java @@ -0,0 +1,122 @@ +package com.amazon.alexa.auto.voice.ui.earcon; + +import android.content.Context; +import android.media.MediaPlayer; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.amazon.alexa.auto.apis.alexaCustomAssistant.EarconProvider; +import com.amazon.alexa.auto.apis.app.AlexaApp; +import com.amazon.alexa.auto.apps.common.util.EarconSoundSettingsProvider; +import com.amazon.alexa.auto.voice.ui.R; + +/** + * Alexa Auto Earcon Controller. + */ +public class EarconController { + private static final String TAG = EarconController.class.getCanonicalName(); + + @NonNull + private final Context mContext; + + private MediaPlayer mAudioCueStartVoice; // Voice-initiated listening audio cue + private MediaPlayer mAudioCueStartTouch; // Touch-initiated listening audio cue + private MediaPlayer mAudioCueEnd; // End of listening audio cue + + private MediaPlayer mAlternativeAudioCueStartVoice; // Alternative Voice-initiated listening audio cue + private MediaPlayer mAlternativeAudioCueEnd; // Alternative End of listening audio cue + + public EarconController(@NonNull Context context) { + mContext = context; + } + + public void initEarcon() { + Log.d(TAG, "Initialize Alexa Auto Earcon..."); + mAudioCueStartVoice = MediaPlayer.create(mContext, R.raw.med_ui_wakesound); + mAudioCueStartTouch = MediaPlayer.create(mContext, R.raw.med_ui_wakesound_touch); + mAudioCueEnd = MediaPlayer.create(mContext, R.raw.med_ui_endpointing); + + if (mContext != null) { + AlexaApp app = AlexaApp.from(mContext); + if (app.getRootComponent().getComponent(EarconProvider.class).isPresent()) { + Log.d(TAG, "Initialize Alternative Alexa Auto Earcon..."); + int alternativeAudioCueStartVoiceRes = + app.getRootComponent().getComponent(EarconProvider.class).get().getAudioCueStartVoice(); + mAlternativeAudioCueStartVoice = MediaPlayer.create(mContext, alternativeAudioCueStartVoiceRes); + int alternativeAudioCueEndRes = + app.getRootComponent().getComponent(EarconProvider.class).get().getAudioCueEnd(); + mAlternativeAudioCueEnd = MediaPlayer.create(mContext, alternativeAudioCueEndRes); + } + } + } + + public void uninitEarcon() { + Log.d(TAG, "Uninitialize Alexa Auto Earcon..."); + if (mAudioCueStartVoice != null) { + mAudioCueStartVoice.release(); + mAudioCueStartVoice = null; + } + if (mAudioCueStartTouch != null) { + mAudioCueStartTouch.release(); + mAudioCueStartTouch = null; + } + if (mAudioCueEnd != null) { + mAudioCueEnd.release(); + mAudioCueEnd = null; + } + AlexaApp app = AlexaApp.from(mContext); + if (app.getRootComponent().getComponent(EarconProvider.class).isPresent()) { + mAlternativeAudioCueStartVoice.release(); + mAlternativeAudioCueStartVoice = null; + mAlternativeAudioCueEnd.release(); + mAlternativeAudioCueEnd = null; + } + } + + public void playAudioCueStartVoice() { + playAudioCueStartVoice(false); + } + + public void playAudioCueStartVoice(boolean alternative) { + if (EarconSoundSettingsProvider.isStartEarconSettingEnabled(mContext)) { + if (alternative) { + if (mAlternativeAudioCueStartVoice != null) { + mAlternativeAudioCueStartVoice.start(); + } + } else { + if (mAudioCueStartVoice != null) { + Log.d(TAG, "Start playing voice-initiated listening audio cue..."); + mAudioCueStartVoice.start(); + } + } + } + } + + public void playAudioCueStartTouch() { + if (mAudioCueStartTouch != null + && EarconSoundSettingsProvider.isStartEarconSettingEnabled(mContext)) { + Log.d(TAG, "Start playing touch-initiated listening audio cue..."); + mAudioCueStartTouch.start(); + } + } + + public void playAudioCueEnd() { + playAudioCueEnd(false); + } + + public void playAudioCueEnd(boolean alternative) { + if (EarconSoundSettingsProvider.isEndEarconSettingEnabled(mContext)) { + if (alternative) { + if (mAlternativeAudioCueEnd != null) { + mAlternativeAudioCueEnd.start(); + } + } else { + if (mAudioCueEnd != null) { + Log.d(TAG, "Start playing end audio cue..."); + mAudioCueEnd.start(); + } + } + } + } +} diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiver.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiver.java new file mode 100644 index 000000000..9ed14acf0 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiver.java @@ -0,0 +1,78 @@ +package com.amazon.alexa.auto.voice.ui.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.Topic; +import com.amazon.alexa.auto.aacs.common.AACSMessage; +import com.amazon.alexa.auto.aacs.common.AACSMessageBuilder; +import com.amazon.alexa.auto.aacs.common.DialogStateChangedMessages; +import com.amazon.alexa.auto.aacs.common.WakewordDetectedMessages; +import com.amazon.alexa.auto.voice.ui.common.AutoVoiceUIMessage; +import com.amazon.alexa.auto.voice.ui.common.Constants; + +import org.greenrobot.eventbus.EventBus; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +/** + * Broadcast receiver which get AACS directives related to voice UI changes. + */ +public class AACSBroadcastReceiver extends BroadcastReceiver { + private static final String TAG = AACSBroadcastReceiver.class.getCanonicalName(); + + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "onReceived"); + if (intent == null || intent.getAction() == null) { + return; + } + + AACSMessageBuilder.parseEmbeddedIntent(intent).ifPresent(message -> { + Log.d(TAG, message.messageId + " | " + message.topic + " | " + message.action + " | " + message.payload); + + switch (message.action) { + case Action.AlexaClient.DIALOG_STATE_CHANGED: + handleDialogStateChanged(message); + break; + case Action.SpeechRecognizer.WAKEWORD_DETECTED: + handleWakewordDetected(message); + break; + case Action.SpeechRecognizer.END_OF_SPEECH_DETECTED: + sendAutoVoiceUIMessage( + Topic.SPEECH_RECOGNIZER, Action.SpeechRecognizer.END_OF_SPEECH_DETECTED, ""); + break; + } + }); + } + + @VisibleForTesting + void handleDialogStateChanged(@NonNull AACSMessage aacsMessage) { + if (aacsMessage.payload != null) { + DialogStateChangedMessages.parseDialogState(aacsMessage.payload).ifPresent(payload -> { + sendAutoVoiceUIMessage( + Constants.TOPIC_VOICE_ANIMATION, Action.AlexaClient.DIALOG_STATE_CHANGED, payload); + }); + } + } + + @VisibleForTesting + void handleWakewordDetected(@NonNull AACSMessage aacsMessage) { + if (aacsMessage.payload != null) { + WakewordDetectedMessages.parseWakeword(aacsMessage.payload).ifPresent(payload -> { + sendAutoVoiceUIMessage( + Constants.TOPIC_VOICE_ANIMATION, Action.SpeechRecognizer.WAKEWORD_DETECTED, payload); + }); + } + } + + @VisibleForTesting + void sendAutoVoiceUIMessage(String topic, String action, String payload) { + Log.d(TAG, "Sending Alexa Auto voice interaction message, topic: " + topic + ", action: " + action); + EventBus.getDefault().post(new AutoVoiceUIMessage(topic, action, payload)); + } +} diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImpl.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImpl.java new file mode 100644 index 000000000..fa64a59e8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImpl.java @@ -0,0 +1,48 @@ +package com.amazon.alexa.auto.voice.ui.session; + +import com.amazon.alexa.auto.apis.session.SessionActivityController; + +import androidx.fragment.app.Fragment; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * Implementation for {@link SessionActivityController}. + */ +public class SessionActivityControllerImpl implements SessionActivityController { + private final BehaviorSubject mFragmentAdded; + private Fragment mVoiceFragment; + private boolean isFragmentAdded; + + public SessionActivityControllerImpl() { + mFragmentAdded = BehaviorSubject.createDefault(false); + } + + @Override + public void addFragment(Fragment fragment) { + mVoiceFragment = fragment; + mFragmentAdded.onNext(true); + isFragmentAdded = true; + } + + @Override + public void removeFragment() { + mFragmentAdded.onNext(false); + isFragmentAdded = false; + } + + @Override + public Fragment getFragment() { + return mVoiceFragment; + } + + @Override + public boolean isFragmentAdded() { + return isFragmentAdded; + } + + @Override + public Observable getFragmentAddedObservable() { + return mFragmentAdded; + } +} diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/session/SessionViewControllerImpl.java b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionViewControllerImpl.java similarity index 96% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/session/SessionViewControllerImpl.java rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionViewControllerImpl.java index 7f4e0301e..eec070e50 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/java/com/amazon/alexa/auto/voiceinteraction/session/SessionViewControllerImpl.java +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/java/com/amazon/alexa/auto/voice/ui/session/SessionViewControllerImpl.java @@ -1,4 +1,4 @@ -package com.amazon.alexa.auto.voiceinteraction.session; +package com.amazon.alexa.auto.voice.ui.session; import android.view.ViewGroup; diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/layout/autovoiceinteraction_layout.xml b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/layout/autovoiceinteraction_layout.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/layout/autovoiceinteraction_layout.xml rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/res/layout/autovoiceinteraction_layout.xml diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-de/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-de/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..121df3d7d6a45a86372e2cec66f4ac8f7e408d58 GIT binary patch literal 29997 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 UO(ESm(<*Yu|L4#8e|h`=1?;nXk^lez literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rAU/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rAU/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..189bb3e22356c937c15301fbf52ab0232c78880d GIT binary patch literal 25245 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 L|6gYOzbE-GQp6+< literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rCA/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rCA/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..55f2d26c5e7045ace36db0bafdad39b02138dc99 GIT binary patch literal 27405 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 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rIN/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rIN/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..585799f05fe023f79a342407c3802498898ec9aa GIT binary patch literal 28989 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 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rUS/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en-rUS/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..4d51167a6391ae6654dbf2804c5b1ffe50ba6f3c GIT binary patch literal 22797 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

{Tj*8H+WOxu8?UuAo*3E|T8 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 C5Wh13 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-en/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3372e9a2d69873a6f2399908fd8b69cd2b6b58aa GIT binary patch literal 28989 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 mh($5T$^+48ng8!J*#CG=k32|bTmNsO8(^WTSC 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 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-es-rUS/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-es-rUS/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b290828f3eec56716a3ac98543cebb9fb22b31a0 GIT binary patch literal 31149 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

2tJ!e7t)r4|84^q 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 EUk|cuaR2}S literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-fr-rCA/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-fr-rCA/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a979c5c99c4d2c729e1e86477623b56549d895f6 GIT binary patch literal 28701 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 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-fr/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-fr/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..e48f7ea94576f3864555a8e273a30cca93bf380b GIT binary patch literal 24381 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 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-it/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-it/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..5de2afac7051c5251237db2046f40fa3df8c0132 GIT binary patch literal 27261 zcmeF&bx>PT`!D+74nd0qic65fXU#W586QQ!4p=j1QxzS z0s_Ym({PW@q4)1@ksb>L)>7o+;gSbo0wCvh4>?#V#9aFWql~`W9u!O7rHt{%y)Yc5-Y*`Qn9$?;GssSim=kRHG5pIiVo4pd4f-sE6has|hRW zygUF?vrgKX+@ux-*?zJ5?-fwi~ ze!W>9@IK^t{;?8-y&_V(V~g6;;c_06a8dAqOl!zU&!{*wiediN@ziw%+4 z{qp+t(;>m#HKx92>+TY8K#Nb;$ZCj)xSBEwmUGTsUZx0_HIuHb_15~6bR;FZ338I| zJrCK@wzmd=6i2LqUPV+4>fs`lsS{?M3)4of)xWH}ye8omQ~TU@LEF%HH9Y*Y0Y$Vj zVR4j>TL(Q|db9#Pgho-Pt82_p*itBHc=LBl45JDyNG(^Jq^G0`8K)F!cKFAaKhBlT zku&qAa_DnPrW+^Ah7P?RA?do+-R8=~x>_zQYwxs8X~o-S(uRu?$<4DSg0>

Elv-KuN}FHJij^@*o+ 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 literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-ja/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-ja/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..4afa6ef30e8f5ef4bbf329ce0186c5cee3d76e8f GIT binary patch literal 33021 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 Nl;!{4Y5%`x`admsE$jdQ literal 0 HcmV?d00001 diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-pt-rBR/auto_error_offline.mp3 b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw-pt-rBR/auto_error_offline.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bd99193763530c21227af6de2b1b14b3122259ad GIT binary patch literal 23373 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

<#&9x|4sZ& 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

{Tj*8H+WOxu8?UuAo*3E|T8 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 C5Wh13 literal 0 HcmV?d00001 diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/raw/med_ui_endpointing.wav b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/med_ui_endpointing.wav similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/raw/med_ui_endpointing.wav rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/med_ui_endpointing.wav diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/raw/med_ui_wakesound.wav b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/med_ui_wakesound.wav similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/raw/med_ui_wakesound.wav rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/med_ui_wakesound.wav diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/raw/med_ui_wakesound_touch.wav b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/med_ui_wakesound_touch.wav similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/raw/med_ui_wakesound_touch.wav rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/res/raw/med_ui_wakesound_touch.wav diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values-land/dimens.xml b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values-land/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values-land/dimens.xml rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values-land/dimens.xml diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values/dimens.xml b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/dimens.xml similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/main/res/values/dimens.xml rename to aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/dimens.xml diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/strings.xml b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/strings.xml new file mode 100644 index 000000000..6fda7afc8 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Alexa App + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/styles.xml b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/styles.xml new file mode 100644 index 000000000..798016545 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/main/res/values/styles.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/TestResourceFileReader.java b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/TestResourceFileReader.java new file mode 100644 index 000000000..10e24cafa --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/TestResourceFileReader.java @@ -0,0 +1,25 @@ +package com.amazon.alexa.auto.voice.ui; + +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Optional; + +public class TestResourceFileReader { + /** + * Read contents of a file from test resources folder under test. + * + * @param fileName Name of the file. + * @return content of the file as String. + */ + public static Optional readFileContent(String fileName) { + URL fileURL = ClassLoader.getSystemResource(fileName); + + try { + String fileContent = new String(Files.readAllBytes(Paths.get(fileURL.getPath()))); + return Optional.of(fileContent); + } catch (Exception e) { + return Optional.empty(); + } + } +} diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiverTest.java b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiverTest.java new file mode 100644 index 000000000..63399cd00 --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/receiver/AACSBroadcastReceiverTest.java @@ -0,0 +1,132 @@ +package com.amazon.alexa.auto.voice.ui.receiver; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.amazon.aacsconstants.AASBConstants; +import com.amazon.aacsconstants.Action; +import com.amazon.alexa.auto.voice.ui.TestResourceFileReader; +import com.amazon.alexa.auto.voice.ui.common.AutoVoiceUIMessage; +import com.amazon.alexa.auto.voice.ui.common.Constants; + +import org.greenrobot.eventbus.EventBus; +import org.greenrobot.eventbus.Subscribe; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; + +import java.util.Optional; + +@RunWith(RobolectricTestRunner.class) +public class AACSBroadcastReceiverTest { + @Mock + private Context context; + + private AACSBroadcastReceiver aacsBroadcastReceiver; + private EventBus eventBus; + private Intent mIntent; + + private String receiveMessageTopic; + private String receiveMessageAction; + private String receiveMessagePayload; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + aacsBroadcastReceiver = spy(new AACSBroadcastReceiver()); + EventBus.getDefault().register(this); + eventBus = spy(EventBus.getDefault()); + } + + @Test + public void handle_aacs_dialog_state_listening_intent() { + generateIntent("aacs/DialogStateChangedListening.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceUIMessage(Constants.TOPIC_VOICE_ANIMATION, + Action.AlexaClient.DIALOG_STATE_CHANGED, AASBConstants.AlexaClient.DIALOG_STATE_LISTENING); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_VOICE_ANIMATION); + Assert.assertEquals(receiveMessageAction, Action.AlexaClient.DIALOG_STATE_CHANGED); + Assert.assertEquals(receiveMessagePayload, AASBConstants.AlexaClient.DIALOG_STATE_LISTENING); + } + + @Test + public void handle_aacs_dialog_state_thinking_intent() { + generateIntent("aacs/DialogStateChangedThinking.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceUIMessage(Constants.TOPIC_VOICE_ANIMATION, + Action.AlexaClient.DIALOG_STATE_CHANGED, AASBConstants.AlexaClient.DIALOG_STATE_THINKING); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_VOICE_ANIMATION); + Assert.assertEquals(receiveMessageAction, Action.AlexaClient.DIALOG_STATE_CHANGED); + Assert.assertEquals(receiveMessagePayload, AASBConstants.AlexaClient.DIALOG_STATE_THINKING); + } + + @Test + public void handle_aacs_dialog_state_speaking_intent() { + generateIntent("aacs/DialogStateChangedSpeaking.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceUIMessage(Constants.TOPIC_VOICE_ANIMATION, + Action.AlexaClient.DIALOG_STATE_CHANGED, AASBConstants.AlexaClient.DIALOG_STATE_SPEAKING); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_VOICE_ANIMATION); + Assert.assertEquals(receiveMessageAction, Action.AlexaClient.DIALOG_STATE_CHANGED); + Assert.assertEquals(receiveMessagePayload, AASBConstants.AlexaClient.DIALOG_STATE_SPEAKING); + } + + @Test + public void handle_aacs_dialog_state_idle_intent() { + generateIntent("aacs/DialogStateChangedIdle.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceUIMessage(Constants.TOPIC_VOICE_ANIMATION, + Action.AlexaClient.DIALOG_STATE_CHANGED, AASBConstants.AlexaClient.DIALOG_STATE_IDLE); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_VOICE_ANIMATION); + Assert.assertEquals(receiveMessageAction, Action.AlexaClient.DIALOG_STATE_CHANGED); + Assert.assertEquals(receiveMessagePayload, AASBConstants.AlexaClient.DIALOG_STATE_IDLE); + } + + @Test + public void handle_aacs_wakeword_detected_intent() { + generateIntent("aacs/WakewordDetected.json"); + aacsBroadcastReceiver.onReceive(context, mIntent); + verify(aacsBroadcastReceiver, times(1)) + .sendAutoVoiceUIMessage(Constants.TOPIC_VOICE_ANIMATION, + Action.SpeechRecognizer.WAKEWORD_DETECTED, "wakeword-SampleText"); + Assert.assertEquals(receiveMessageTopic, Constants.TOPIC_VOICE_ANIMATION); + Assert.assertEquals(receiveMessageAction, Action.SpeechRecognizer.WAKEWORD_DETECTED); + Assert.assertEquals(receiveMessagePayload, "wakeword-SampleText"); + } + + @Test + public void ignore_invalid_intent_action() { + mIntent = new Intent(""); + verify(aacsBroadcastReceiver, times(0)).handleDialogStateChanged(any()); + verify(aacsBroadcastReceiver, times(0)).sendAutoVoiceUIMessage(any(), any(), any()); + } + + private void generateIntent(String resPath) { + mIntent = new Intent(Constants.DIALOG_STATE_CHANGE); + Optional sampleAACSListeningMessage = TestResourceFileReader.readFileContent(resPath); + Bundle sampleListeningPayload = new Bundle(); + sampleListeningPayload.putString("message", sampleAACSListeningMessage.get()); + mIntent.putExtra("payload", sampleListeningPayload); + } + + @Subscribe + public void testOnReceiveEvent(AutoVoiceUIMessage message) { + receiveMessageTopic = message.getTopic(); + receiveMessageAction = message.getAction(); + receiveMessagePayload = message.getPayload(); + } +} diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImplTest.java b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImplTest.java new file mode 100644 index 000000000..85237c22a --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionActivityControllerImplTest.java @@ -0,0 +1,67 @@ +package com.amazon.alexa.auto.voice.ui.session; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import androidx.fragment.app.Fragment; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.observers.TestObserver; + +public class SessionActivityControllerImplTest { + private SessionActivityControllerImpl mClassUnderTest; + + @Before + public void setup() { + mClassUnderTest = new SessionActivityControllerImpl(); + } + + @Test + public void testAddFragment() { + Fragment fragment = Mockito.mock(Fragment.class); + mClassUnderTest.addFragment(fragment); + + Fragment returnFragment = mClassUnderTest.getFragment(); + Assert.assertEquals(fragment, returnFragment); + } + + @Test + public void testVoiceFragmentDisplayedRunnable() { + Fragment fragment = Mockito.mock(Fragment.class); + + Observable fragmentDisplayedObservable = mClassUnderTest.getFragmentAddedObservable(); + TestObserver testObserver = TestObserver.create(); + fragmentDisplayedObservable.subscribe(testObserver); + + testObserver.assertValue(false); + + mClassUnderTest.addFragment(fragment); + + testObserver = TestObserver.create(); + fragmentDisplayedObservable.subscribe(testObserver); + + testObserver.assertValue(true); + + mClassUnderTest.removeFragment(); + + testObserver = TestObserver.create(); + fragmentDisplayedObservable.subscribe(testObserver); + + testObserver.assertValue(false); + + mClassUnderTest.addFragment(fragment); + + testObserver = TestObserver.create(); + fragmentDisplayedObservable.subscribe(testObserver); + + testObserver.assertValue(true); + + mClassUnderTest.removeFragment(); + + testObserver = TestObserver.create(); + fragmentDisplayedObservable.subscribe(testObserver); + + testObserver.assertValue(false); + } +} diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/session/SessionViewControllerImplTest.java b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionViewControllerImplTest.java similarity index 97% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/session/SessionViewControllerImplTest.java rename to aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionViewControllerImplTest.java index 5c8477344..ebb09334c 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/java/com/amazon/alexa/auto/voiceinteraction/session/SessionViewControllerImplTest.java +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/java/com/amazon/alexa/auto/voice/ui/session/SessionViewControllerImplTest.java @@ -1,4 +1,4 @@ -package com.amazon.alexa.auto.voiceinteraction.session; +package com.amazon.alexa.auto.voice.ui.session; import android.view.ViewGroup; diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedIdle.json b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedIdle.json similarity index 91% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedIdle.json rename to aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedIdle.json index d5e3ed1cf..94d1a24ba 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedIdle.json +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedIdle.json @@ -1,6 +1,6 @@ { "header": { - "version": "3.0", + "version": "3.3", "messageType": "Publish", "id": "testIdForListening", "messageDescription": { diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedListening.json b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedListening.json similarity index 91% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedListening.json rename to aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedListening.json index a908c2ee7..f010e23a8 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedListening.json +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedListening.json @@ -1,6 +1,6 @@ { "header": { - "version": "3.0", + "version": "3.3", "messageType": "Publish", "id": "testIdForListening", "messageDescription": { diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedSpeaking.json b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedSpeaking.json similarity index 91% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedSpeaking.json rename to aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedSpeaking.json index 671f1024f..32aa456d3 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedSpeaking.json +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedSpeaking.json @@ -1,6 +1,6 @@ { "header": { - "version": "3.0", + "version": "3.3", "messageType": "Publish", "id": "testIdForListening", "messageDescription": { diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedThinking.json b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedThinking.json similarity index 91% rename from platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedThinking.json rename to aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedThinking.json index 4b13eb96a..67a1b216e 100644 --- a/platforms/android/app-components/alexa-auto-voice-interaction/src/test/resources/aacs/DialogStateChangedThinking.json +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/DialogStateChangedThinking.json @@ -1,6 +1,6 @@ { "header": { - "version": "3.0", + "version": "3.3", "messageType": "Publish", "id": "testIdForListening", "messageDescription": { diff --git a/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/WakewordDetected.json b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/WakewordDetected.json new file mode 100644 index 000000000..cf114f6cc --- /dev/null +++ b/aacs/android/app-components/alexa-auto-voice-ui/src/test/resources/aacs/WakewordDetected.json @@ -0,0 +1,14 @@ +{ + "header" : { + "version" : "3.3", + "messageType" : "Publish", + "id" : "id-SampleText", + "messageDescription" : { + "topic" : "SpeechRecognizer", + "action" : "WakewordDetected" + } + }, + "payload" : { + "wakeword" : "wakeword-SampleText" + } +} \ No newline at end of file diff --git a/platforms/android/alexa-auto-client-service/assets/AACSArchDetailed.png b/aacs/android/assets/AACSArchDetailed.png similarity index 100% rename from platforms/android/alexa-auto-client-service/assets/AACSArchDetailed.png rename to aacs/android/assets/AACSArchDetailed.png diff --git a/platforms/android/alexa-auto-client-service/assets/AACSInit.puml b/aacs/android/assets/AACSInit.puml similarity index 100% rename from platforms/android/alexa-auto-client-service/assets/AACSInit.puml rename to aacs/android/assets/AACSInit.puml diff --git a/platforms/android/alexa-auto-client-service/assets/AACSInitFlow.png b/aacs/android/assets/AACSInitFlow.png similarity index 100% rename from platforms/android/alexa-auto-client-service/assets/AACSInitFlow.png rename to aacs/android/assets/AACSInitFlow.png diff --git a/platforms/android/alexa-auto-client-service/assets/AACSWakeword.png b/aacs/android/assets/AACSWakeword.png similarity index 100% rename from platforms/android/alexa-auto-client-service/assets/AACSWakeword.png rename to aacs/android/assets/AACSWakeword.png diff --git a/platforms/android/alexa-auto-client-service/assets/AACSWakeword.puml b/aacs/android/assets/AACSWakeword.puml similarity index 100% rename from platforms/android/alexa-auto-client-service/assets/AACSWakeword.puml rename to aacs/android/assets/AACSWakeword.puml diff --git a/aacs/android/assets/AACS_CBLLogin.png b/aacs/android/assets/AACS_CBLLogin.png new file mode 100644 index 0000000000000000000000000000000000000000..dbb6649013c68d0a6175f59f94913c0352b1a36e GIT binary patch literal 86098 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

_tb$7$So&wu}Lo4s2V!xp?l)XRE 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

+ +

+ +## Prerequisites +You must meet the prerequisites described in this section before you can run the AACS Sample App. + +### Requirements for Using AACS Sample App +The following list describes the requirements for the AACS Sample App: + +* The app can only run on an Android device. +* The app requires AACS to be running. You can obtain the AACS AAR according to the instructions in the [AACS README](../README.md). +* The app requires the Voice Chrome extension. + +The app is optimized for and tested with the Android Automotive operating system. It is tested with Android API level 28. + +> **Note:** The AACS Sample App requires hardware accelerated encryption on your target device. Almost all hardware-based security concepts contain this acceleration. If you see a performance issue when running the app, your device might be missing mandatory security features. + +### Requirements for Using AACS Sample App with Preview Mode +Preview Mode is an Alexa feature that gives users a restricted set of Alexa features without requiring a login to the Amazon account. To allow users to use the app with Preview Mode, obtain an app component `alexa-auto-preview-mode-util` from Amazon with the help of your Solutions Architect (SA) or Partner Manager. Follow the instructions included to build the app component before you proceed. + +### Requirements for Using AACS Sample App with APL +Alexa has a visual design framework called Alexa Presentation Language (APL), which allows you to build interactive voice and visual experiences across the device landscape. To allow users to use the app with APL, follow the instructions in [Alexa Auto APL Renderer README](../app-components/alexa-auto-apl-renderer/README.md) to configure and build the app. + +### Requirements for Building AACS Sample App +The requirements for building the app depends on whether you use the command line interface (CLI) or Android Studio: + +* CLI: You need Gradle to build the AACS Sample App. The tested Gradle version is 6.5. + +* Android Studio: The Android Studio version must be 4.0 or later. Make sure that your Gradle version and Android Studio are compatible. See the [Android Gradle Plugin Release Notes](https://developer.android.com/studio/releases/gradle-plugin#updating-gradle) for information about matching Android Studio versions to Gradle versions. + +### Requirements for Using Optional Features +To use optional features delivered by Auto SDK extensions, contact your Solutions Architect or Partner Manager. The following list describes the extensions that you can use with the AACS Sample App: + +* Alexa Custom Assistant extension gives the user the option of using a custom voice assistant when running the AACS Sample App. + +* Mobile Authorization extension enables the user to log in to Amazon through the Alexa mobile app on the user's phone, without requiring the user to enter the CBL code. + +## About App Components + +The AACS Sample App APK contains several app components, each of which consists of the compiled source code or resources used by the app to provide the UI layout, communicate with AACS, and so on. See the app components directory [`alexa-auto-sdk/aacs/android/app-components/`](../app-components/) for the complete list of app components used by the AACS Sample App. + +See the respective README file about the purpose of each component. + +## Building the AACS Sample App Using AACS AAR +To build the AACS Sample App, follow these major steps: +1) Clone the Auto SDK repository. +2) Edit the configuration information for your device. +3) Include the build dependencies. +4) Build the AACS Sample App. + +### Cloning the Auto SDK Repository +Follow these steps to clone the Auto SDK repository: +1) Create your project directory (if you do not already have one): + +```shell + mkdir ~/Projects + cd ~/Projects +``` + +2) Clone the alexa-auto-sdk repository into your project directory: + +```shell + git clone https://github.com/alexa/alexa-auto-sdk.git + cd alexa-auto-sdk +``` + +The Projects directory contains the Auto SDK directory structure with the `android-aacs-sample-app` directory and `app-components` directory, as shown in the following Auto SDK directory structure: +```bash +. +├── aacs +│ └── android +│ ├── app-components +│ │ ├── alexa-auto-apis +│ │ ├── alexa-auto-apl-renderer +│ │ ├── alexa-auto-apps-common-ui +│ │ ├── alexa-auto-apps-common-util +│ │ ├── alexa-auto-carcontrol +│ │ ├── alexa-auto-comms-ui +│ │ ├── alexa-auto-contacts +│ │ ├── alexa-auto-device-usage +│ │ ├── alexa-auto-lwa-auth +│ │ ├── alexa-auto-media-player +│ │ ├── alexa-auto-navigation +│ │ ├── alexa-auto-preview-mode-util +│ │ ├── alexa-auto-settings +│ │ ├── alexa-auto-setup +│ │ ├── alexa-auto-telephony +│ │ ├── alexa-auto-templateruntime-renderer +│ │ ├── alexa-auto-tts +│ │ ├── alexa-auto-ux-restrictions +│ │ ├── alexa-auto-voice-interaction +│ │ └── alexa-auto-voice-ui +│ ├── assets +│ ├── common +│ │ ├── commonutils +│ │ ├── constants +│ │ └── ipc +│ ├── sample-app +│ │ ├── alexa-auto-app +│ │ ├── build +│ │ └── gradle +│ └── service +│ ├── core-service +│ ├── gradle +│ └── modules +``` + +### Editing the Configuration File +For Alexa Voice Service (AVS) to authenticate your device profile, specify the configuration information in this file: + +[alexa-auto-sdk/aacs/android/sample-app/alexa-auto-app/src/main/assets/config/aacs_config.json](alexa-auto-app/src/main/assets/config/aacs_config.json) + +The following list describes the required information for `aacs.alexa.deviceInfo`: + +* For `clientId`, specify the Client ID that you generated when you [set up your security profile](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/register-a-product.html#set-up-your-security-profile) for your development device. +* For `productId`, specify the Product ID that you entered when you [filled in the product information](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/register-a-product.html#fill-in-product-information) for your development device. + + >**Note:** `clientId` and `productId` must correspond to a development device profile that you created as an **automotive** product by selecting the `Automotive` product category when you [filled in the product information](https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/register-a-product.html#fill-in-product-information). +* For `deviceSerialNumber`, specify the serial number of your device. +* For `manufacturerName`, specify the name of the device manufacturer. +* For `description`, specify a description of your device. + +### Including Build Dependency (AAR) +The AACS Sample App APK requires the Auto SDK Voice Chrome extension (autovoicechrome.aar) as a dependency. Follow these steps to include the AAR: + +1. Create the following directory: + + `alexa-auto-sdk/aacs/android/app-components/alexa-auto-voice-interaction/libs` +2. Copy the AAR into the directory. + +After including the dependency, you can build the AACS Sample App APK either on the CLI or by using Android Studio. + +### Building and Signing the AACS Sample App APK +You can use the command line interface (CLI) or the Android Studio to build and sign the AACS Sample App APK. + +#### Using the CLI +Follow these steps to build the AACS Sample App APK: +1) Enter the following command to change the directory: + +~~~ + cd ~/Projects/alexa-auto-sdk/aacs/android/sample-app +~~~ + +2) Enter the following command to start the local build. + +~~~ + ./gradlew assembleLocalRelease +~~~ +This command builds the Alexa Auto SDK, AACS, AACS Sample App and all the extensions present under the `alexa-auto-sdk/extensions/extras` directory for armv8 targets. +* To enable the local debug log during the build, use `assembleLocalDebug` in the `gradlew` command. +* To build AACS Sample App using the pre-built Alexa Auto SDK AARs, use `assembleRemoteRelease` in the `gradlew` command. + +The `gradlew` command creates the unsigned APK, which is located in the following directory: + +alexa-auto-app/build/outputs/apk/release/alexa-auto-app_release_4.0.apk + +The `gradlew` command also creates each app component's AAR, which is located in each component's build output directory. For example, the Alexa Auto Media Player AAR is in the following directory: + +~/Projects/alexa-auto-sdk/aacs/android/app-components/alexa-auto-media-player/build/outputs/aar/alexa-auto-media-player_release.aar + +#### Optional Arguments +The following optional arguments are supported: +1. Enable Optional Modules + * To build AACS Sample App optional modules, use `-Penabled`. For example, enable APL by appending `-PenabledAPL` to the build command. The supported module options are `-PenabledAPL`, `-PenabledUXRestrictions`, `-PenabledPreviewMode`, `-PenabledDeviceUsage`. + * To enable AACS optional libraries, use `-P`. For example, enable AACS Telephony service by appending `-PenabledTelephony` to the build command. The supported module options are `-PenabledTelephony`, `-PenabledContacts`, `-PenabledCarControl`. + + See the below for the full command to enable APL, UX restrictions, telephony and contacts: + ``` + ./gradlew assembleLocalRelease -PenabledAPL -PenabledUXRestrictions -PenabledTelephony -PenabledContacts + ``` +2. Specify Path to Extensions + * By default, the builder picks up all the extensions present under the `alexa-auto-sdk/extensions/extras` directory. To override with your custom paths to the extensions, use `-Pextensions`. See the below for the full command: + ``` + ./gradlew assembleLocalRelease -Pextensions=~/your/custom/path/to/extension1,~/your/custom/path/to/extension2,... + ``` +3. Clean Cache and Rebuild + * To clean the AACS and AACS Sample App build cache, run `./gradlew clean` first before running the build command. + * To rebuild only outdated dependencies, append `-Pforce` to the build command. This option is required when you make a change on Alexa Auto SDK. It forces the builder to re-export all the package recipes and triggers rebuild for the packages on which changes are detected. + * To clean all the Alexa Auto SDK cache and rebuild all the dependencies: use `-PcleanDeps`. +4. Skip Dependencies + * To skip the step of building dependencies, use `-PskipDeps`. Make sure the Alexa Auto SDK dependency AARs are already present under `alexa-auto-sdk/aacs/android/service/core-service/libs` directory before you use this option. +5. Specify Architecture + * Specify the build target by appending the option `-Parch=`, for example: `-Parch=x86_64`. The supported architectures are `x86`,`x86_64`,`armv7`,`armv8`. If not specified, the builder by default builds for the armv8 target. +6. Enable Sensitive Logs + * Use the option `-PsensitiveLogs` to enable senstive logs. Note that sensitive logs are allowed in debug builds only. +7. Change the dependency cache location + * Change the location of the Alexa Auto SDK build cache by using this option: `-PconanHome=your/custom/home`. The default location is set to `alexa-auto-sdk/builder/.builder`. +8. Automatically Accept Licenses + * You need to manually accept the Android SDK licenses from command line when you build the first time. Use `-PacceptLicenses` to automatically accept the licenses. +9. Specify Options for Dependencies + * Use `-PconanOptions=:

Pr$k8bvhc|N49t5r>;v<90QpkY!Bp~++wTqziGeaf=*pE~ zEzp`EHCIsAZ-C8Shm;*Kz01oFFhL-6e!0tUg|P>DZ-U3Bc_<&lTT8WS4YJ65=pjKK zP^$m7uWudXqE*wl=AOVgZn7;A5FbWTFdPHRModwsxEliVJpTrbY8Qtm{67d*RNWU~ znE`NBSXc;~I}C{9q6i3zV4;Uh7RtxR-fe64D!L&NyEzm%Q&+O7`3mEtpbxu~$i9D-G4W&LK=vqe@YfbMfmh|XRH zU<6r`x?{+ayc$ID6bK_*$0KgwAZ-lVTwlzuULG7AWV5Gb^d&re7-pUEqv#q+OXzOy z4J~>^#>7~3PeMlbT+23$&e0OyStK?y-TeMN!}E?!rzt_)9swev;_%*@2W^b#Ju-`* z2>U+UYuOi~)5AJG2H#;|U_eY-Hv<2}$lmTciVifPvMoKccSAPr-M!n`*l2|gBNMe7 z`?$I3Dx6$)3--Q)wK3G)&E+OIR{4M<}R5w@{hXz&apVb~at_^u`*L8609h8T2^YbER?dKYLmUBDo)zs8L z>a2l|%5{?vfVV#ks~*z~S%ve~>)XHqgJ|chsB6*Y`Z$5W-T^$<08vHg0htA~#8tvm z!%mLf$M&Dgj~C2O`P3#}AbxAR(WLEl;{FnMKLmWNZxl5KJgT>VnkF~xMk=JXnRr3E0XsU!85;n#s@^36oJ9! zI|&0_>l6&$D-a;+lRYkD51#XNx`c}i4)0VlYO0o3ZFkw5*iCBJ{j~Givd?^~6?gi3 zlVJZ*I=O9=gn{s~Ah~@fZ4$n-{+`w%&Gz7d+9Ph8ViJ^u``aJabhT3?zi_}CDM6WL3o4hOx~el-Kl z7?SjnU&w=jU(g;Szr2`jeE*}5+i!;c{Wxw__+Ka3@AC%a1s?1-g81G?Rx4XJQB2>g z&D_lF+uEA7mDRkEZpQ+L=%aigqh#8&U=YrL>gG5l4>M??xw#8JSh|5u1|l=eDG(MC zYK8fjIXOA3^P&2)&k=4G-*65;y)W}OQ4SmjPK(!i-B40mpwORPc*P+kv!-$)VjK1*jPmmb2TCVcXkpn)mkg z@$>R(AQ;xa9Uz%I)IBS?+(8D?`URI_IzEAlwNu(#rh{~e*gWGqu_N>Rkc3lAY5oar36Xf<;!ye1Gv`?C{AIrvx9>J^i|ic zy#vLuW8?tzw`}$RX9H;p(+B`HXx*KPi52&(Ieb3)^XJdc{ruESfUDF<`d1AF9dphN~z8=G($stgI+Vu(!!#u zx*Fq|2ld}En3FPbFy~RY34>(AYSfi`px z8?%11S}9w%;@=*OSQ{LexCZQc&c63M9c8NPgIX>|!+dyJB z79}Q*0AGsg4&2ncNP>_rKU<(_pf6zF0kyb?o|7ZWq=y$7q_8ts%#7DK0ir7#S!5Y` z+p6GAg=JBpx8_KrE6DtSW9ShiX@b_4ndSvAs>|CuQ$a%F1B6v;MC>Ci+zcvOKHFid zJu!3Wgl3>_0J$D(7b<(AA|7^V4a@<LC=(6J z@kF-Kefds4I;Ug@*lrfJv>Qlom$N`><4MN9s0y?=CinFX0dw7NOPE*V7~C(97_+dKFz0@7_Li=ZU1D?DtL>z4;hK zpTI?%CFD8w8Fz1henqx>9VosXnQE4571IO4t1IOf{o&7FoKIijts5SZDc!E>}GECxUz2Pra zsH;`nT_$Emw$b$;On0aDV&Zql)hEWC^H)|;`Hi^I^0 z9?TL*HLO(Uj?Mh_hp91$5qK{6a`V15`NULKA5KGE1*D^gLqnxiiB!7m# zOJcGAvgOc5{7m()Q4zpLL$3|3Rv>dLe8aZg&pRj*T0Z=v!$Nn(fDT?|yW`EJ{N8;m zSFiGF@fkgdAY!FLJ{(Vlnj zu07a=TBcZ$fss*2P;e%%u4D(aYakgQqT*u{6N9FAIBNwMBalbJokPn2T|6qy!L9g5 zYJOQ%#FLz2(IYWL#Ef|kk$mX7w&EOL0Z`etwu=C8#Dr-zL3akRiBVIUkWg+c~o9f@(@mQ1vgBg4i_IE_M;Ce9*mtu1-OQXh4Da= z1RyV4D?d-W@DsgnwrDrTOIEm|OIr8J-H*=!M<2SGYq_t=o-MQh6;dwW5v2Gg@TyNs zN`eF03Ntfjya_!`<}nz32!Xvnd2SU?9yhF&?C31lekQJ{!h&2-55{?gP3IZ4LQ02I z+E`W~r>D4?m~QM9hL%*v;P6fJ>{nW7c#u&=$->q}r$I7c3x|s7>&Ne?Y=bsJ+P%he zuZBlMPj9<0amNaR9OBPGu8G3}WKNoNe~rApBcTiW=^`Wr4{do9(#6qo8QsWMJ_B{e z`Sa(OHBKa=YSus=iPbu~pMfKI7Qz@kwXeJNrtc4gML;3WZG736=4h<2FYr?`UV zEFgy}!WB~7Bfj99WpUE(V$biz=ifn#M0Rq&2aEhk0thu-{|wjtLfwCxXZg3R3M#MY z`%X@r%*+CysQ?u)UpLgm#-^s(b}Ia&!`j*!W_R&u7#P@evYK1}k`93vub}zd+^h#{(FT9jfcm*asJIl< z?=^+&V~06AV5cY`xAuy}!b%6{6fG&K1lbf=eSUCOSGA~Ju3x{dlptcxTll}&1+`VE zX6ZA)5^Q0+nM-vS8d$I-kByF=BqK9&By>z3%yuJmY)I`?HkVni83Ut8h(5d_5)u+* zP$D=#Rty@Je{#YA6eSZG85=`+00eD2Xd9%^Q!w# zJ+SZxMkr{pi^6o7xSTvWeQ%@96H1+F zIMLb5y5xw)A4K`K)W3vg8_CsK>9_2a(+o=5WJ-jz(F&+ z*ce~hwbCXIit%g4LKiPeXvTzvr99edU`m8}2x1CMq@<+a!v~vSGm?o(#qg$1*RP*{ zbi_S88d_R?vrpSKsoao#e2xA>u5~$5OZ^Mx* z-I;2L>eGh?D(ZNc6OM0ck<4km1=|gbGSojEQW}>3nQd)ga4}f6Ve`$SinDu)&mOsv zJ@fISBrvX_aRV|E>)O(>oPIE8?)Lm4F1yuf6)0J+-1`KR0o#D0>Hh9b=OJ+C{b6Ea z;u)WY-T}>d@!hZDWP1|U#FIJ%Qwk|z~f<#JE^7E6A zTie@@w&rdx`=TGdO+iW1e1+(QY!8PJMAlsG*2lb@3G*n8LJncfU;mq=&6xI+H0uhC z%7cDeO+y3D$?Snas~MQZp-M2zZ~i89(|8PrK!Y0G%*^a_V;IEJf^d6k4+6wnwCaHL|TJ;0I z;f}S6x2~&!x9jCa5DjrzJ zn?9|zua(QyL}%PXyw2c-JyQoaU`n=u2z!8<$ERb32Z8Y_dZq6W;Tp4Qt*HH^Kgl;n zP`AHp;OkI~y8H^b*L~?5pYYaRV)V`Okz4ZeenKPA!^qfSj9tJpv&oj+qD8(1!&@EG zG5%xH0rDp%iVIEWtXO*o2f^USrhCFRBT7eVM$n(WUfl;=~U`Y!d?cj3D zkHTdA+>6L!czQIBuj93E-C_>b-Qa!UQtT-F2M!TxcL6^hhe1`p#dvmBmg@Wa*)w$+ z*BWeRH74k2AHg}4FV1s)fzG=+v;54JlfEHVqm-&?qp7d-Cnf$v8ci}74{j+za zV{P~36enZ5HHAkKPMfFiEiCSG@bha`JGnYK7K0rTMD&}@+-*gfk|^_uu_}aJou3cs zV9lFPM9Pxlp`JhRrJx8%(QYob8k20$H#4tKSnyV#<;AJoB;N0<+_+9rQ$GT3(Kroz zJr&>cD`?VpSb~2j1kqZJSom`5_+c1X*To}Eg!z1_tUbITwSC%GwN>_D6>704OOORr zVNGU$Cky%Dx#VX!EvDi&=RCv*j!(#u^qtw_Av55JXN@e-#lVGfC`Sf@g-uMM_!^ll z_m8x6wNi%mXav}_CxU!@-Y~&!?6>a+WL0;-WCUGy z+LP4r@o|J548gO5s_4j#P)5Z|%*^cu!`+m4soS_uV=d|uCntY{jWIdpx!tzJ`I=cX)n9Fbl3=2R}z^$55g_)g! zab8Vxc{dUmmfC)$8hP8`_Bt+ca3qMh6eK1Zf~>G!+Ag%kR)(z9{ir|XNQreU=mNq0 z1UK02R*o+3ghqvKXIiE)z3ViTw;@wKb8V=n3`$5nwD{5nomLeCV-<=}ad?0MZW4mn z!VBwMKE&~_^c~+)PJa$gpY-dj-QCXJN9fh_djAaO9=I_ zFuZL=U}XWT>FYxV_Db(vrA0o3e*6Q`K6f$5l>(_gRu6m$Vfg$7H>3b!&!|e~XOWmM zXQO-h)n!LvEP`_sp~NxV)_E=O?qa+&TMFY1+8q4V$0T8hLBX@O901?P5VJFUI;auf z$9tz&#ay{>u^9wRK_t(QF$~AnF1VmbUjftrQu*g&G(V>sKpDNgF16h5+5FItApoaj z6F$y=8jsY!>E3a(4iKaEkHQbvp6C7Zx2bg zrKYFDxYOM1Dwp+-&u@?s{z7bBwe=qZ;9c4>Gdmlmzg{RNse89U{8Kn}m2A%zkT`&Y zpKMw~gWVkL^B>K#fqMlTcq8`}RE}vq^+Uy$ESE01ZqB5Kn-B4UWFBa$)N7zJ>+V($ zW#}R-|Ruq_Xi7-$iO#qg0)#!w-SbYfr%(nIdTJ5FGyG~$^`QG8Z2XeWl-tM)qToJ z5Mz)AQgtKNWBQ^dR6s;`Ufr%36O43KhHSGh5_h{W_WaaE@IB?cFIVx@%+q7B>w}}{ z#7b@DixDR^h9Bpoo*_3Z<&91dbKeBRzwsu}*U*uIl8W10G16u#Tm#{%4Lx_(;K1`e zm;lja0RDq<9Ku9Ma219Cw1yS2&FC=xPzZ5dfl^3TuTdEfsrRIVDq4aOd{;$^19 zU#~o=x!c;lIqHhs%|0$|H{C4}U_m=ORaaU{#}*g&U}nON$)a@eSw|}vaoX3P#%|p; zm!U*e%y?Af!i6#L7Cl-hpF&!;DT7xa)R^!oU}EkH`DWS@BL!3z(wDqub$}`v=`0xy z+%UyKVw*P@{~)5ysCFI(9ee2E463?tAH--iI~C!G4$DXJSQe!8=*-U-!XRxhdBi4_ zN%p>eeHm(5P>l7D(7}a7ns-Iaf--C0iM-5)4&X9J9IiDmE8PiW-hxdgg*n1mUfmFQ zf}w^(V!~}LGFuy)1OdA-fPBEs!PLc7-_{0GhU_PmOJfkY0TYx`92IqTLg$T5EU>T8 z#h1pIx1lie_Aqy9*=3&2DsMa%4W7>omE`%wAUM6WsmNU35nz5GfZt?g$;stzT|Zm= z5C|HW3xY)^YlBV%W{$P!;#DkA0MF)MPC+5`9umkZlgfV4#Y~_fZ{T(1%$|P^S&%vX zNMl%;pQfw|YdA0k4Q&GGd7z6HbHmO9WInG~8Sfqu4N)LBHQK91`KT$`CwwwAs^1y$h;q7l@eOdUe>^dDh7!*uU7%G}2S zkdz8Ps4zp(U|7#miQU3tLZczTEIYznyoY&1yJG1nDbBcbdE;hxNqfGbcqoYrGUcbJ zmQq^3lcQ^aU4#E4RJgyU&SL%kEZ!Me#MRup051p%j^GXHT#61%m7kwHtnJ&kN5Sdc z6D?^cO^b`Uf$#8;=quVu_zTED$wa@4TDoQT9jr9}wTSjV=F?QI*dbBmmzYmLFf_i? zIckCmT4h8BEfEdV6wDGWdQOpzpYMC`-iPzRK$4NPgK`v+M7))N>Gq7ih(;QZ<;F*n zXn-IvStbZ%73!X@U|fk_DXra6^oR)!1qJEWSGqlcD_2zX&*2rbKtTBgK_ix58lVg$ zDoF5w=v)TJoVw$IR9+m+nWdTCqYB4c>;-~@6q^33S2ZoTXMWC!NMoO$lf1a=|BZCrg&)f zAT|O7_6W=#LT=ccP8aQ$KLw&HRQ$6gvhG%;qQ3&65WcO7T^p&B^JYs-y8l1s-aDS_ z{r?|U8mFlt4WUz%vdWB%rddge5E{0Sc-yPvw1~12LWLr$>@Agq?7c(C&febF{q=s! z>3qJw@9+1!ez)toUDx^ZRJ_LX^?W`a_s4yZl{gw(mzVVim9MkD2B(^gzsAiQirER5 zFIZe`$Q35|4#Z6n%Vy!Guwne=>|A96=FDi7vgUrmMT(sd^d3R`X>-4)2e1D1NkUua z%o(@jROMgcAM4av4%f9aHv%?Clc>WxO44>ZK69rfz* zL-w^m$h<`JUzc(_LA?6%cjfCdO@fcw>I;V#*vlIz)tOTeOYWVMMQBs~9zT4|=!pWp zsj*S(8qnMNl4PI;EpN2_LS}|cBCB^YF_HH8Z3$UHkUCw%sie-6d!Ip;!?IPG(Il~< zGxK6nCZG#ymm_Ovp;QtcnHIf$EW2v8rPZ;AkfYQG83#z2dIfH#kZpFse+bkQv3)Kr zu$!2J=dgsktE<-ol*w}dN|bz45xK-Whpz2&US8qf3;l{J02FjJDFZu3hKDPwD>?F` zJGq-y5D=*yjhe#w^SpqN{T}P!X}*C%rg7**F($wiRi-nFYI=oq_`EMmQMfW46^E>V;#%QU9PsEktiTbY?5*U|*%=ecu_1vln?`sDrO ziR?`qP|m!+V}TMrKIpdl1uhxc)x$91AE$xVn~-7mEXB5oL5F8`CuQrqt~*d}bP%W_ zc;8u&#+G+Nk?pR_<)vs!a^ZFF|xC#z@9IR02!7LU?yl$MC>2+m@=j zPBnbjMx9f>j#FFnyWnDyCAd-M<}hf5UoC)xkg~KUsS2GjzVAvy`Y?`)a{@AM2eErL zZ$)k{8#sUm58eb-u;=s7JWc~j8<0@%Qd_A6JstJqMZoUBlas)@0;7skL zDW$ElQ<%=>5!8L;PXY=lRtVQ1(73T8M}tnXZnp(@N>U-?%$YhRIx5i9gop#bSnVpKY5Fe6voUSl&oN2iCAf(A1Zw%rn5muLmU;j=l7~O~2xk|8izzyoA z{m@_1isJ((IhxbV11B-s+q)1R~fGs*P%Vn+&>X@G0*UU4}&DW7L_EYftO%&cQ zt!gNRw^Phsaz~4f$f;LkcFqd@v`rtZ;oi`$AOYgfAN0RwZBE>WS2tyyGriVImSH(e zD%ni7e=_?{&U`$)7T|9L-7g9hVRGgqC9t~bUwU3Yzv2pXApez0^jho?o8hMs%pR#c zH_DulCh*Ye{af?R_Hq_jwAUYA_|aCDl$oKEvC!(O-)D@}+MZxqEP|-i)`)uO;Q!(t zC|mb$DP{}UzWU|5u#2Pn|NJ> z1m^sul5M}N@ogUTOL}FBVPl3PG(nUawX1BNU1NNJr{4c_YT;6+Jl6%8$|*v1HptGc zSz}y9L&E_Bt)U3ChsQxJSb@1)7Mw7 zB}@Ji*Oi3x+Q%KH`{D=O-RIy4B+%IaEJ7GhEo7HG8W&xn+L1OM?91lj_J+PkRg5 zzIqMM!|3o!rrqVe*|XaB73f(GeRvW6<6=W(ktD~(z1OZ~K!iJJXjr4AQ_Lt_F5@@# zh&;Ku|8;K|ZQ+wMysCGmCqJ_2NC%NeD}2f0$wKqfHM!-we%9lChGk{fU0liUVg{6l zNz>*f7hcboX@!K|D-jc#{&1(pa9(qKKrF_kx0#$>M$@|K*zV`Acl~us;r9JytJ>Ci ztk$bw?NP8jdv3G9nRYgV(K3@;%zNi6G#mJZWwOOqrEc(US6+59LZD6k;j!?S>^s(0 zOYORrTX<~wRo9wX@uCDX3*=~gm5iCT5g&KX>$|EGEnrxpYMUKcbZG)KSOwVOR}3lG zp}?uuf0oWk^W*Z@<1|mLX;#oHH0sdDzM0N-T9Rqfc{3edy+&?a zd?7wdgs)Bc?P2KO^AGLuR1MmhYQv=Q^ z%!Ye@UL|^2xw^3`Ca6aMn`(> z=Vy15+&E`uCX5Yi)MWyEe0U=L#_w$XP)YwLRm1+_wz60}tb*a90FE&-U;OB(x5M1! zBB8ezBjSEmUYKjKF*H9@^g%6oJ|dy9vCG?}Mq=Xf&0{%h0}oV6Nq^aFJE02oE^lb; zu$y^@f~ts+u=V5OW6PIYGfT{$@0yQo$3|56<;%IOR}LV?X3vksKAR&huk=*NWLL0! z()#jaM$tm9Szekp-T7&0H3trKmOMRlQo?1h zZiG*>C69W6rLRk_AF=rA{Xyu4m6B4B@Q9hVz1c`Xj`Ixtmdp*z17VtXrXPRYdAQWR zA;}SLXc3QpOKYI^or5fIGU;5L!{p82*esizSyh{rQbX`G zk)|*C`t@sJAwrWKFJ9cDD?wbic^UgWo(rggTuSp(CGk@3vs>BbWIwF^RKpt1 zk%Xw!=2;JqL)!11nw?jS)uoZrqS<5YLevU84mMtE?QuUJmz?YxtU1^+yVqfA`04xi z;Wz=ne5dgd7VWU!ZtTH?(FD7>vBdV)wqeTtZXhYki|#Q#9<{#ZKaRz zL`ENX14k9fj=rS07=b?o=#kyUy@p1FF@6J$4zm-~2{rC*(KE5}4FX2Z@~yfhS@p@W zW+y%lbB{?pwp60;A~VyJrapyL=m^bP_Lq|$r(_3({XFzm-=A z;trRKkWlQ}Ro2Jnf@{IxqMl5hOWr&6I4C?L$Qf4T74N^&9z^Zml>@P@FLPB~Pb6kKgzb^vn?zcYF~-`?w3P5X2wa} zT!DsJVas%cWB7D6A|h?!`xjoL`KauM8plhkfSO$50a`9Tz{^KmdY9Fkbukotz*kx| z_VKQ@j9^l)BUADvrP#HMjbixbSZ|K$tJJy5$lU&HxOV;c5aDC%vK;G->VI<#iVmChyGz@zGiFY1_UW#vtLTY=APx=-q9=Tud_ zcsDdQ^Po*~zM$SNGaw*js;d3&U4%fL{cOmIu#fK7jtDUuel2lExtjf6#4YSqHNkd; z<3c7eiot?Hv5InfBWb7=u{0B zROeih^;*6^iKKA3PM!J0-BAIuq>X-eBX;A@hKkJH-TUXJ=jM)#A3GM5_b9uvN3C?- zj>;}#(|?_q=(=*fxykD^kwY$WYtoBl(9P4+(^o*>`>|A-%M+nf~spVRK$ECj6uPMe$V5eL$RkcN-^ao`K-FbzMhcd6W?os41LL$r@PB)N@6EW95!d$S)ac0{NB8B zmiEjNS{u3@mAbvv-ATJUT0ffY-edpQU!rWjNxNNQ)n_*I@N6AR?yVNv%+%CUH&yoY zW`O0nng|7~jvEc*u|2Z+Q*c>NURpF*Vf@y}^F0J4rufX_(&=XkH9x;;sWl;~tN%lO^YM**Vk-ni9Do-%+&EEtWL-`4SPtLZ1uK<`3O)gWM3^4M*po1uHUYjGcMzm% z*igLb?XZI8B((PV^XG6PDY{lv$g_X{c8D#|tu31Y-=~`;@N8#-22U2;$cEeoBTYd0xuqBPI3VB%Ed8}R2#w)}4R0Y|10_)A4gBuPIF;;G z6%-Bu3x*ml;Pl?9?JO*g;7C^|mQK^vCvNd6cEjy+#3z<;d&4~eZ*Rh^qh^1Lq z9w>yn8BB9NPgE&fxWET)2A*AE+^qMtl3)p*LcqU@D&i-KQ;hDtA0u7N)whylIH zrP3wgtXy(wPYB7j*wlBgiIzVNDp_ENjB)?#ihO_d7Z=hqjn=PO6B!<^mz({9I0gwg zPGL6drIl+TCJW@*mL%bAEfcnI?Qm>&6XL9nRZWzwmYeFSdF^)6R7fZpxJ-EOnY~`= z>9(%Xyv(`rad8Zsmv*fILsAXGx&ZV0aX(??6VW1E!+9Z|<6))o+af&p&WRZ6iEz@C znaQ+4Fc3ku1N#fHY>0tfN8tW2J9>BVkQQuPtbWX^mdF{G&MBlDM>dbv307|ps zoMak12Zx-DjQ&S24;uT2$Al<*BVds`DB$!lc z*L~Z%lE&DG#r6%(5lDhNicJR40$S7*LkLX zcb+FSSnqCuY~SlZtPl_-P&dkb4iYr-*Li2)27V;i194&bS|V87a3B3jR?5h&PTH26 zo5$h^Pf{|0_FLOv{mx?;@&+?zxk7=$%D&Zm5*csAN5NbhPA2x++8t0(KWKZql}x*O z;ou(>RLD3Yo~BQqZQrDr8S|~W>aNmB(^a>@%Iw)8At*aPK#@!AG2$&_@gLK|8wB!+Kn*2PwcYkPG-!m?0S~OS=54cBwAVfbk%ip_H z$?X=5h>B=DyO+83Zpp%Yd}c6%!pF+Z&JHiV2@{&HqBOLt12^Y3HSTN>{Y%xm?!g^V zQH6|wo4Kva$(mV~~UMSdM^9qriN=rGscIS^EpRo%?HzK$LG}kKD z^wo{TKi?%!NB4Skl%C}K;e%tqVbkZYyRP$OY=DrMH_%O>P_a-Yd;awvsd?8M5>_{Z zNxebus;=}N=VyHEHFEi=lT=C2qgvVG>Z<&Z@E>*j8 zY>m{o(GtfXG3()7&g+t@oU-f#<>b2RS10&a1s*=c^XJuXWg$GMS$%`s^XLv+^qo>c zWL|#UF;wR!+4dcYH7~2`jV?BICmUVhcJ4}ZpShl`RVP02t_-kDzng6)&EipS+^bgo zIb<@`Y>jqnXOT}&?A`VK912P*SyrYpN1g5!e->Au$*(XMUPg|Z4d=-APpAz%&0X8w|*p2tWoXHsPFlFx(+c>6Jz$Xk+B+wNd`H8 zubS_CP}9)B#xrOwFlz9scXTxWTUGPj*94eQSm*t~&OQE^f z2cy_yQY>eR>-w6G?AH8Z`f#RUUBk|H$nWr9slI~fp6f1uUy{gf&Yn60r|CntZ#$A3 zIzQg)Iw?85Y`L}UO@T*6p30dSm-z=RjI%f+CL>-?A2}jn&|CduMPXxx^&9W@&Q5j- zm}u*ZtV?45q(plX3+TI1(P=~VK+)=G+r1*wCa3P)BUdn0hOyDE7-i-UFR6~MP!kM&_$ zO4&?Y;5Wa|Ma=-OVru@bnlj_I1B<)IDIAX*7aJ0y4eEloAO&Zm^f`wg88hY*5L$6A z=dy+N=0O{sI<+S;f6Z=OL;g^;m#nSqdS`MnCFn@&9KkqNBczw@(dpnS^iAmT`KK0=UPO5D#Dk`(ugB^;O z_Z9l}N0fSnMz4jPd2829hc7usyeYm*H}11&3eryOE7>)-ZoPM#wkbZ&!9dhy>z2%2 zr-YA49N2F;GrqlNTEOttTBdrUYP`pCmbazsnu_Ws`tRMXt=>UFFQdMGoy~u^{e;$w z7gtlG$ejVp%ik3GYI+HjNU#i(=UezX?~EP{x$tVZHq*BHN15Xhg9j5U*UzR~^Ffl{ zefu`^@Z&q`={l&(^RR)8bVf`ER#chvA;llAjKfc&!VlzEFj@u(Q=l<4|`8@H> zrr$LDH>Z}aMC4_MwU(Dj7c}lZ_no0wu7J#Nm04QXIgrpwC z;Y~Y?*R{kjJC2rx;t{B)#wk|g^p!O2<@Hg^TDPrq=Cj+DI8F)LrJ}___7|Hvz%msm z(%utzPI2_FlLN0_)sRF^zP^f81eBQaSZ%I^Os0`az6MMrb0otz_q!u`LZ0)lFji1y z7dpG`kJ>!lVl_2m#C>M_1_oHy5Xe+7_MOgKii+7{whphFkIcgQ=}^ zOeBY}%g=-+SjZc7-^z#tUbqnd6Z=4+{M`C76Fz)tzq%;quk6i@8MkT=#sXS9aU%G! zw(Dtj>tS>{a-kWdLiflvG<6rVow%sGtFu-sI>^x`OULZa8>Sm;zYM$bi2FU=cEurn z6wR{qdd;`H&YMZ;$2<7p8=ILLdmFZ*O}&X%Cs-SCVq_Gk*bdg>HULhYZwKZI=| zDZ^(5=jWQ{d$S#G1g`pLL*7qzto7rQ5ZaVWwC?y&Rt2wHSNLeB-w}(b;7up_cwc=D z5V|aT1iSQCzZ15A31Zmib5=g+B;WHBogXC6y^EUq`BA2taiQgVWm?25LAD!S!}GTa zzqo+FjsE)JZTiH8UFSCmJ$o;~ke-6bZ2bq3ac#rBNJ&oXIgl=Yh}Tm6eeY%VN8J$A z`de%E(=qL8$}$Hu<@m}P?7yh1GxfQ&-MK>^{}CeQWAZw(h1ORzR>M)S6fpAr`Re&f;LQsO|SJj)%%w)dEAT0U9xtJK$vz8$T(;>b0nUfbs#$lU+Gv4ho0; zQa~G`oi=+?x{n6<-NGT3&Vs>bFwGT)r3+mEMGQ}Ik-(+@ zryk()RuEC-iJx|qu~-!DKc$xilg+w{k=&+{X;WAKTxK>G={QuQg*xtEo4)zRFoO_nX-{7+UzDp#!ocT=p7-c-8 zqe?`6+-G;_{JLGh8&bo959kc5cy7Cb9S%JMuGaaKitqDgr_9_F zy*Sjl4v|rj#b3Ta?7`ASOEqE;+3h0l&mRFwR8rD-YFE&O<2OL?y?puEvMXNs3(}3m zX_MS_4B9!=9vazXvX`K#fXx?ZRo)#C|&OR%zOrpbQW=V+h49$F`MUF*vYmU)vFquK~-k7r0FI?OUjT?%+2^@rWi zmiZ{emyw={M)7zO{OK-Q7V5Y4)Y>UYzTMimUHjXYJu_vsjd`D+YO?AAdiS%SZV6ZP zI$NPnniFS!P}e8c-Ile7AOfpldQJTe*fMH6hHqalu&g9oT+HaI2x#2*eTLP3F7hE` zBKhMl0aQK5Jri>#-;vs0=*Q{_)I{XQSfc1mhb*wxSS5}6qI&uP4%mC;uI z8}H$TgJYw=0e8^+32xt<2W>{6ApdLsIYJMILCTJ@P~-i_{v<57O_&A`4BHhAVG&1c z8vkrogAOoN`}Hh{2_JRzP6gu^Sjk{Z5qsKCd5eL@?K^hVLzT%aHqd*0+jp_NTZdlw3s#1Vx4nY8y=lMy+S`bY!~z@G*U+%A)U>n%@^m{7KYsf3M|ZcMzkhvg zZTOAnyeY0<3Jce)U5iZ3*VdOjJ3t?U0ti7D4<9~cVAN4Ck&(#` zd03R*&z{*~QWnSORVdUxL;|%w0 zh>3Ab!FWd_^;Xy^E#555!R-qR3Zi;F-5@M!Xo(0fu7Dfva zpe|48c$TsX;?Pw;la%D1YsKj4>B+hq5d%ie87fVa&UE6BwZORt5PBC7HWc}_s`|>* zYp!UMGf|cZmx5i7rYLeU4Y=ZbqskgN#KhDc)YR0#!>j`i;ewRCIi z8T$;|5gEJlPe2e}N=s{WYKXxSw}D+S;`E+jCI6QegixB4mXnXdo zl8`O9tk4@cjP+b3(FR_B7rCz54PF~iS-r?L5m2tL687gvS1n1HEN`fy>r6zhm6DQD z0YUi-Lh^!|Ezs$Uii&#Uw8Wn7zWAAy_W0$AemyKK?B_UD2OLs~-o(`RUt6jF5mipL zx6Pl6iq6bABp#&f#XUOz?81E_PZ*pppE-jp05c?A`ILM6ocG=#b9#AI8zKkr;0mh(wqV1e?xs?RaGKLsk9XND#7h|E+!!qaL4c4w{P&o?J>E2 zbL%NdNlCb-sXlBIF}h&VAa4HS+?Z|6OMu!SDP@F%{Oky|T~Ezhx1DmXM)#rA#$eRQ zD4PF7(_wyobFfPp)C^)0BF)T|ECPe{hr*I0S-#4pLyC6k(j{x_smFhw(5kD}fEors z>V+r$a~edH0ZJp~hix#KeDLrg&~w4;f;TL=M*T0@IXPj|Yeb?)#9nbpi83#dNr4kU z>+IqQpfYV)_SOLLC+$~T5Kt#e;{rDz_(Nh4Z z(LNR=_u_)${_W`+HtEwjFP}V;m``ye&$HN%dYqk#yEQ*MHSD6Oq*VM&*o&GwNRyV( zP;;iLceSy)QRyn><4ZNbgT>e&I`#x(%PEjNWe*sV=zTADb##Oo`}z0?K(`ygjt^=? zytRdVGx8_q>m04oxz`VA4pc?@l4yDP_}E4PJ`*7(5F>5l*Lxi2fDZ0_+%NpJSTdnUv+k0}e z9F{cEtA{fM9{G=za4}lBSl{*fb&ZoM{1VPA|EOd9;}CD2DZTJzsiQ~Vqb%!QNmx-Q z)Bf6wou3Y|Hv|TL`PqojV6> zLBr<5wv9DvUG@VGmMV=1uHr2o%8a0#)7@8LCjAVL9dQMGwY5 zhH(R&jUL|U?(EdbyXU2_2d8+omws%!4b5A%o`#anxxjBI*XlE;?Kc9pED)@CF*yWy_YK2L6$d zBc18rpHNIfa+XKW+Ul58H+N9Vp`i^Dv-PhroRd{C_uh&9#v?6r=l!U6dUn)fai=<- zG>nxT@~hXylXi*pXJAGO-95CMawKOI*zlP1%GWYU))Ult^W>J68&L^*vKM!;P%uGa zF+7j_dYmBVBMkd*27#?I-{mm=`+eMJl=~Ftf$Rp)JD4Pcjod9|+Pmp{grXu`r7mCY zYi|#UidsA<*?jWlALv4udM;TrLC+)faNwmeV{dOCERU6J($s+v& zCO@{YlY+nPjVm?6SH52nkn`%m87-$=I1D2s=sh|V6Oz^V8Dka2@EVa^-U*MJ*oq6;Zv`DsN!%;d>h=B9>19;z=LQB0S!EF&W zX@UOhQtYPU#*|CPEDtenJaPQ^6K?ebeizh3Mr8dg6)`B&)(+!*CPM0gBs(G86dY_E zxD2Ga1F0Q!CsbD&M)J#iBUU09?E6kXy$SM=lDVr+yAM-G?s@XN{Mj(Am~SJLsWN3F zE4`!h0$&RIc3A7?&qh`jXlwLt8-W1lk{y>F3_dWp>eYS_*F!S7%InwI)TGv^URhlY z!{$QyG0oMW%R?v-x$~^6(ZNfx4lz$ew{P5dmGWM8dk8ExNd-HcV{xQZLo%XuwK>BY ztzmMl@9S*x+@PDc&YbQa{%*-XZsR-Lx^?Tz!@-WkJ~Mml zJ*8r&Yv#mbu1vQyQTc<~LFr_qS`G&7FoF3wroo}}N`SiN5W3g%WYa^ga&OhYqAwjG zPV<0P>S-R9%g#Lpt~k2ra6{H7u^O4GJ9Y`|(09(U84HrQszj8 zdeh4~tFRtSki*G;zi3u^{Oc=%v8SB0tgMLD&nwrjx5ok+>4LM_3=8)oH08)+4A5j_ zXl`zXMVzcB5f}n{$5RSms%fAx<3#*Q!2r(sv(nNB=_ESYYF!ekBT-M6GkXb-PpFJ^ z=Y<-QmUa;jTxz6cyt_gd&UM%XQ3SwMRGRSghk0sPPRXSt1-Duibcg_5047YN%+?xxPtqhDB8kwS;1So{KHTh%iME> z=S+cw-KV@fxm6-z`sFt=&L@s~X6)Y79cE|SziNteSd-^tb;97ldww1sP;lIOIa?szpOn;%DrCItAq!Eu z3@a)dWSy_R9iN)2qOoy=^+r|^BIZIj0En4NCG{$$%T^0-7;)p0^?HIX;b}{~Jt{pY zh&{)WWaCf858V>SwcopUZ)RpDlH)-ewbLqni`p7v^3nxr`O%eVqyYU35fna!%e4O| zC+@dDpWdne9#d&VGVH}lM5{2~Q`IZJrmwMS3Bg)hPTioKRKgoh4xtfx`EvJI_Bvo4 zcJl;NX=vrjh2KglVxRxA=TSoMF)RjH^DpdfG&Bd1nnQ=EN73R#=eVo5|BxY7tlfa5@_`I5&9Vx-ig>ay_`1qnV z?|iOnXC{=w4Bi^ao3~-C@at%l)TZ^xQ9rqeL2=ceyL4&W&YgX&tuTpr5tG2KIbu~r zcNOkH*q+LjMb?!@t)cSD>2A>z9t?<0GlP>dydmVceSFZ$ptXa0Ea6BxG^CIO(~V|O zJu8_YGjN_9Bc{9yD>7)G($x%^X)41zWfbpcHTr!G3HI?M9+|&o}48Xid zaY*x@GJ+6?n_BdUzEzk-8B#EeO6Kz;7L&}|ap#a}y=6;S4EkJAq_a$|Alzf5tJZ1F zz~V_Q47<9Fx6vU7wZ2FV8D^MQ;P8sOtgO6s+crH8m*f;2xnE!}!nk7xr$q)7Fr3m| zwbQyw1KWLynjuGoNM1A3=3>*)*G2v$Oxf`LeY=gu5K5JJ$c2bK6zm7WmJ$!vj&@ZK zBE!7zz`$^%Hi9!HH8rB;6T@Dw{HCTRC4GWVqG>6#Ew@TLjNJ$Ba?$L~ZQPKAl5X6H zf*=BnUVh7j#2dX<_}vaO{fI^axwfuKhX5f?ng&o1g>Se0?y$}T3Y$r;3xfzGZUYk& zkrM|?Nib9V?tO&W9!R-z3_*_bgbBK8Xdb~5ZYgDe7#2?^N!IJB4V79_b!Ef|x+u7A zM`XL@sMCW51#c$4O}SMK@eLvxB;Q}X+SW?91V8rmlm)&a*QiZ=W^|R)N*xBzJ|XCE z;Pd#PphRrqndg?7(e8L$1>P}X91dZZY~3Wx1z_Bbs1BG)R(Br~6BFa+K3g8KNILNj zeWOy3r9~KP0RiBE6_x%^6Fj0iF^j_t`E0vI^962JVq&&!O9LcXD z0X`GtZG@VQ5h|`W?6whwZBM$RYfnkj!3HKI*D3?!Pb4mq+&YI;`{H0!O*Cvn>A8ZN zb90EQZ((cscI@e$p7qK*=ci&vX4o{vZ${y~4qV?A=p`n=_)c#r2?3MLLP|}OMFDxEznZ#SkYF+I2<(={H2$-3F3V}cI z2GRXw4!u5x8yVnT1I0}8x~UpFlNdMJe-&J}buff`aK=l`j!p*D4p5kg9|h;9(`SoO*_phiL)uU}^(N zz?<97*c%%gM;kv?pSgSQp019LRHG*C|tW+13#E~Fwqv;3*VY%3kw4?#_R`#%3Xz1~Zl zHVsNVbp~&WU*P-%;Av2OO~C=%$nVGKS;qRea>zv3U9~+*-Hh=dA9V)3+ogSph{?Qg z5*k|6$|wS7CMWfby+Af>P=pG-rUp(TRviUCpeYKGdK6`v{zawSWqkuuXOKtni~r|T z%Ab&)6Rtk9WJo5HtokI~bCu|8M0fVS>S3ve&!{n`MrJ1=B(HZUn|8kBtbSG`AW)Bu#3*b*pq;*|_IlOwppL?r zq2u*5&vN)Q42_LlT>n}utuoD)j!A@mp~bmIVl~Q|Ko0i-n(CA0L8lTe`{$KhPjjq}v#t<{kI3yx-qz8-JW7v1>wJ(2w z?$1)rAR>d#f}d=J|8FtaOk`RH1aPQ9SevNndjRH4eLhd0S^;CGETpere@$)!AI$V6 zzmzxD6uKD8kwQv*u|?tXwNL_rklcM?0e56H?(K_|kwsJYIJW?RIm{DOYU8wBZ+z?Q z+$)i6-1LU{WC1lmg6-W2ldVgQ0}V0kK?v1EABf2UBp;E=sREChG7e4W-NG&iXc5uJ zTNxO7Mm?iDw+kl>s--#G=;*xqu7USx*=((w>$1gp#X5sW+!wPy@^tX1CG~;TTo4Ps zt>JHTA;{Q{<@fi#;?obX5EoE$@M)*F zyxJAq%|?SK0D%_u^z1L+SD^h5^NZ2WzU;RsAB@O9UvXi4QGs{ggEI0 zhx_J`YbCUGzq&H2=M~)CeUJ8^9Z)Jgye`Euq&H>fy;?4Z5@~8$+j@tCbN~%s9%hzQ zc6W$3`M?v$;&xGDyUA3Ux5T)7gv7;DUBp@fj@aMP+<#=Bvg6)Wb|3c~^874hduI27 z$Z;prF)9U3XHX`Ta_H=GNoIzRZSy_=k31{nizd$E@BVW!CTs(Al`i7HL698(y5;{E z*8}(brLTcBUhZES)p&;E~2LgrAFAIMroJ=(chUbGBoF_3h)zZEub!iI$=2;qEc zBja`LSL$A}7I1UL2YBndaT+adMzm&b)&;n6QWlEKy(Co=Oz_YKuNGIyP3qZt^Emys-W( zhT2XQ%e*{Heaj2jYN!#!@|!~4Oa}jNK$9@T{<6erKxhq|WC(i_|7?+eGXdHsbTmH; z((&QgV1)RR^C8obae(Unx24pRxQ{Wwnj4iqjJjYMTd6K9D=YbkxgY*$!Y#8$M&j)M zU%({;pKZc7JI$sh^tJl-j|3uK8jbe!a3N3CI-oA??d=$;WfG7|gld6@0Kv(Y{e=!? zFj6Z>RQI=T-GbTR6P^DbfRfI!-t`JZnl4NYQsuAv|PJu_1uY zKyru}_q|bA821TWKMjoCX$h@yOBPq*@CCsmj`JCr6zM|?`Da&kPb^ZKyscibQ%8Qu z$~+|opWncf_dzN89>oipfk?xAV5uMCb#JpV2!Z`4w{=0Q6 zdaFvRJokaiu$F+c)L7#HzuQ<_!*~3Q%JrW zxiQ^R-c1NS8A655J8}?Gih?crBpl%k`m$U(N>NNA=Hb&tHx&T6dwP~%qxZGJN`~W2 zrNE{_1QT$rd%VLfA?Hfwv;u**0(yRxQ*UGx!n0>j2qwk_am5_k^P|{wP{qQI=fvH$ z9@?%(u(X2jhKa&o(Vha`JEI)*fx?AIx*?=37FBFyvvqTfaT!3kF<3}eI(|53!U5YY z$~^@3q5kvK5}*DN0zgqVVZKmv{^hbQ`CR~9K+EY=esE`@c3=gw2!)A(!Z)H;h*sOT z242;1GdMgEnfUeNBkNU3*NmuR$}hklbK16@obC ze+Pmc8;_suFoGEz1aHk;JM;f50P?ll|04h-WMIgwgL(KZB?5q4K>LiT{EW0FPV+BeS8Y~LJ~?fXr-hHLx$q}Q)}Pn|9S7gw*m(HPLnE0|tWky?D+XJ;`4G0gpQ zR|b|7!$Z+NVs1+AaO{|2HChvxC7}0a_?U3b{(%CI3+8ChiH5jTW1uPP0sw&dP_}?+ z*1r3*6JP~B{){>S!%-*q=NhafrrQ$BNIMCOh7GytLe!R?o6^!}Yu=iRIDo2+I(EoN zZ{ub{M{g{&MnEYr*3R)G@g%n_02kDm&@aN|e3gRSAHkph-{tBMt%W+J zg$-Hsyu?$3kK4@R z=tf#S;W7pnwry|zVMaC~&eY_ic=ve)Q7*0`-3V@za%&SZ~9mbNhy5NiFshft|5Ywns;#jhH-61vm6?sI99OevfejoNkI# zISb%jjzAkTQ&V8}U-I+I^iMEa^Z`^06>&~9G^WMXE(n5(Jy#xd+4q0et;_uHcI&12 z`Q1notL`P)y#KPX&ZW(NrFPSmIoit!dSw`$o4fa-wy=eZy!M~__eTJErOrx4GRu;f zI2Na*MB_m9f5!=zjibTt;nRR1si}@a1IZJZ9^&)}S^!>RFafyAvz2{F| z>)8ETeW-l8u)NJpsQK-sY=f!;Dm)zld4&v{Ls-Se;@(o3L7(>orvlehYaCLmE0m`D zvC~7{zN&{d!9i6`jgg6oOQOng|5H9)cledvI^19Ot~$^Tvry<(e?u;=K4`;O?7|a# zEI^a>m4$nE7+b>aIAi)cbF{ z_bAdn6gL0v-VZaoun$l%Vl7sg*9+%yjr6(!!$M4>L6P86LKd!V6W!9KOQC!;otq{- z_zR8YVw`Ccj4h8rCSo@qc`W9J$tIIT#4?f zkWANot(=+~WeegQJbwJIvzq#X<=>X5imIbT>eHKVfFmRh0U|OPM#D)_Z{8SWyI-7_ z;H%>}bZ7|q7%L2u6W5_tJW8Jj4+OTOD6}FBSvgNhNfCD5X;n$ZS^l93@cvVYf{B_N zJoD~=eEwwxu)Se3_*?kr`uhe`hk5!MCr|#J>z38;(ssN&?r+EZzmbK3QVKv-P4|+K zz1=Kjka0>q+y-mn%a<;NS12d#(Em=8ZPLBI$Is8t(-wI(&DLFk2u?+oSh$#o(%kxN z@9Z0OaUdPDXY-z4gh;x+xi5|W;kC$UdLByy2o9e#!3=M3o9Sz)+UM))zIAW*lR+=@ z|E_`eGI8{8;Zbq$=@q@ZbNxSk`Lp=Y%<1p9%7*M8tchn~V&gE|*)C|k*Yo3&e}0MC zlLULBbC0(b0{{tX@Cg8-VjQ-c~&GMOTX%K_Rj-|L%;>IC#|( zg5*gT^7+k3p5v5eK<3^#{crL@)@K!Y9%>%3zDt1EM1xNOu?f-0qoM{VT^~$mC54dgyT7* z@_iE*q#rrn1Uff1hPje48Y5cX;AW|0)WLlG{0S(*181f!X5Z@qJJvl;V8@Q{O@r;z zr$gmV4gEtUy7T#e+|=KYVpj0A(N}Gn2Zn$gHx{tbGbftYtXY$8HPm*3`8VGG1EU|_ z@ve*S5Z%4U^_G1wsYzB+Hmb=&4Tq%+!cKoZtMe01mEFgt#UE8pZd9Qn-AAeyk#4E1 zsDAUH#uB*^VvuXdxR#k0l?_$~6+cpEb1D2Upttb9yZ;dNnI7apwIJP0>ng@TD6$l5 zFv`yR^hx?19xi%2;`77~&WnI!{K12qPR;!_H(s3G>(P@nGjOCxQ)R-b)1zKwx2t$^ z6+Xu(Gbgx0Vpiy%c*$Gy+_?=~w|2oOc*BOrUS1&;cLn=u0mn&`Rv6YaN=hwGd`W4Q zS8DWwT0wuXhTj`@foG4Civ1W0%lcXwB9p}V+xML9dhBxt<3YB4`(P#evAL}1>sqIh zzo`>5PeIo<5L*{D1^x}v2Ob-NiGdjd;k|vULl);*fC%Z$-#b;{CmD#~wzy$}am$+Y zJL6W5AyPbgk&^TeclTtk>W}Z=&3mi4ioWPZu6(%D1D-V2=ZG`z{V7+52tV186eLZ> zBm7#00kmFBmw_JRINjWaOOITz|P))pdjupjm3HMtIfG% zlv}oZN7Cc6NT2_cgPesYXo)Vh+RYe6huz*~+s^HBA;YEbigNI!lR0a)a@&zVwoKH! z+=tZ1OFC*n_pqZyS?XWizl#{Ue@-y3A>TijUDqjp;rw~lTj9Nhg@s6^8B^191=OuW zk9~HJl$J7mvhmybC2xEW3D{-R2lEn;rVwD%?&o}z@-uCiq zwxDc#kSJLnq3Nzemz?4neZufv!x-JvKMD;su{1xwB|rT(TseB1-Muj3B9t( zMN zR^DB|7rK1amjAZG z$Ysgf@rYqlCcp@Zf58bi^dnb(4G1+m`R~y{EI*_EPa3ZO*=Qi|*JvQzj;WsD>XbeD z3p2vm~(x|^{PQ(xhXK6)4`k>=GcQ7+AEwtNySoON*zsKw|5DgFA-pOU5o%lF%{ zEil+XKEd>hHLsw<34UU&qxNI;4Y~OhbU5JnQk!7nq@txUdiEKkdEbb=c~=z&u3v`| zhi}b4<7<$DpZ8Zx?tQe1w}G85|9j`wd<=+x5-iz`fbf|=dwe81`M{r6tUB=%p{_IT zsEEGt{YjKv65lBJ%=32j1ET&jwR&u~yV4#OO$3eRIr?25>P-|fAm3ZO7_{(^*96#m zvfgtXYb*eAVGc?V(b|`42#eiD!f*IX815gH(tDF? zHBFa#c?C2vyIjnEv8<_dWve_2P2?YO;R2?QtUIa-UUwC&6sf}r>Ye>-IMGD+AKWfV zX+@RaP<}lw0xSX=nuJ(F*Z}^dyy(zLyex1v-(s+AE2n2*0NBa^HF6Q7)}t94*Nl>; z!R*J(WM~yIXoFdBBMunjk#67uE1$2njU4#2cL{!E|9vX9QpRbH#ts%e^5RpW(2s#5 z1bhg|FXK-T*WLN!M~Y67|G<{2`h$Z_aG=e~nuos+c+nb{F4cnJB;0$yZGn=oKm`9G z8DHwjCdVqx$Wwrl%SPME%1TE^M^RCcL-vRFLSYAb9_I;3#-|_9RJtY z9wsykDj>G507qSoBzZYGGZLvPD);5=f9QV#L8MiV53EidfU@m;U{1Y2a+!y(FNjmM z@w)OOHqn~q}<+MjRuP z#|Ku%xQMint@I6M70Q;4t!5`Hc%0n&U;};G#e9;SQN>*UDZ`2+uIP-&hWd8hsr3Hn zGYv)a`c3p~v44lZ4Q+EYJ+o_1jwAc{$}RNdldG4$d^smB(Pi0H9K^@B_WtnTnBCWp zc?WfiEwj38b;S8hO0GT?upGD?vW*W>x~q=!dcl1d1BelJ*%^_5f)Jn{w0Cg_ zB_tfN*Wu+nR@_UL6(#1XY4a$k*>e3py}>g2?x!2%;Rmvv^s?xvC}blmFxK=t`}EgO zTu7$ny$1SSd*jU?KM7ncRu-In)bE{29w~T5l=HCufkRO@*x)`ybmJJ^dz9z8 zJn(;Y+N*G#goNfv-YV^ukW)kx>EnO!wr)r@cD>KmXmMAjBG#e0pX7HcoxU zp~vDIOryp%j|n-tjNRY1VZ+aIIUbqLgyFOLD-W=;hCY9OR0rq4^fza^`Wx@$gT=u} zW0<&I&to&H5v5@0`5xSU5I%UpV?_~Ib^Vh0kyufMW=?I5O!U&7TI&%r7xVvLCVg{7(b)~;2lbGYxr~!4V`e4_7cW+U zQm7itjR_sj;SS9)$JJ2(b`A{0WIR)yxni2$nW{Rh1;KA_G-LGjle-PAtWr=N!3y?_Kr>z^yp}ZV6+1z$i?-Vx9kV~D zcJG-8u5G#X4s+8HEo--ef{K@rC}~<}jH4CDbK1#kQ(!HJ(#D)f_#x9US%Sy);^r0BGpzXz7jU%GH%Gd;aIH0==26=W2Nz{CqpSdxBDxVHLUp6ZN5 zP&-9ue}2RW?v$dUw@ufS$U0Xx${l1mQ5~GWaKVQaq}Kwd4FgtS@RbH^%Foo&()Trsgo7yP%8U*P z#LYpG2iAe~ftWXMFt}tCyzzA0GRbXe7m~1%7A%!+-W`X90OlwVFO_)k12gCtk|U4A z&WiC_S0m*C0u?>eUdi64dAScCuHCMo-TWgk&ZITuk$4Y8k{LDQyOJl2`Oo?kQQlaMM7F?Xt>WesK@jB$6f2LyVhCjpw0|4-|TPi_kG?c zMwkGZR94-PG|IwqGgcLsZ2jA948Cee+$9vy1QZ?xtR-^mYEj^P$lIELvw8xTf5tX? z`d$c~a~m?=Gom)`l(4Ir_jkZe3--IVF6hr7LX1pI_&3L_7j2}K*=-5}IiYUrgQ`!! zhF8%2Hd#vpMOm zMpIXiS22gBTXkkJX1C7;nZc}7F~_OIIw`BWpM~;3D*QXr2NB62v4QH$ZQ_r_4cj2S zZ8MePlOy3@>D!%Z(yNP5JT6X#*k!2+1LpSKbH_9Azdii)21G|cP(Ng~?K2;T!C6i67qdd!Bq2rjH zn?uZV`?qhkw*?0J^2ANjvBhGcou^~++3?-;Co4Oi#a(px{boRrSmae>J=H7`C2xtS zyq4^AsB~CZo?$B}36d9`8v}o}W-kI-`fc)OLIrMgb$4Tr9C>|x8H9@?W~j5#xOu4h zM0;%)Oo)smZcEH71>D*ZxTAO}evF%ywF~Y8U;hlN%z!y|@ z++a0Mjj3j1^tH8q`?MJU{@Z+NMCah>_Hh*(H6put1C{<35)m3)at*21sDlQS&**MI z{w8!8R)8alfH|gdBKT11h?4SyaeOMH8dW&^zgKO^FiOdrmbAd#fE(k{6tZi~%*-O# zH2V|)&T7K&e`LfWcrVb}bGq7M9`i=8I}Vl@qU0mv0|J(aNw`p@*J6Sq^{K5egnl2E zi}A%CZ`^TSLt_9WCO#ZuXuGc3*bLzWuwJp606BSmK#BK!T;hRQ$8@~$;?}PhQ3r2= zRM4~C+Iw?GER}G3c|5g^mp=>@=I^cEGF+b@m%+D|$ie|?t_2;ioFjUbt5CUCO9oH{}q{`9Vw*HC4It1nwZYgo(ogR$~JYHb*u zCNGY!?L9XwL$eC^0g=2(+-@%CwiZZuF@h<*k2IB3$f#g(8I$!_W^I}npofHTaUxim zgR{P-2AQ_Vl?4^CX>ak*4fiZeOnz>--l|q=YUsPL1a&SRJN5>V<~V`4<$)DZHgp~n z#sbf2Xip4V1_6GkYiQK6WF=O1u|q8740Di2 zlNv_hZteP-9QQtMiEmN4+R1^dcKycU8xxz0uni45f&z!2zs1IGQ+izM%@)=xz-mSo z(vet;)0zkmh(Z$Bepad=(w0~wnuQN;q{TjU{ml|Fn*1hog_oDQa4dg3-ti;y6?MD;Q4}v%dT+jMVtsO z0si6B4_rzHXVHcdvzrQ(7ew5_hvigCe^JF8B~m1EIzgxW*8xCuZ;S7IvAe{d{_%;4 z`t^3H@CLAAoRk40|M_|$x$i%3ls{rY7tA5LspD%MFtZ5*Jz^f)b&%_D~; zPvsF_4e{@=9Z9n8)FzIZASoIqL=`dxi+1)er6RMoRNp&B^{IptN|Uvu9k;li+Dg~u z46;2wXkUovy-56 zz{g-49X}2Uh_8evC7V-vM25w}ra)K~J`4m` zMO;p<A>pxe4Wm&DF9cRNN!6i8#Pv zT;X@sJ#rYu7$!q}yr^Qh54$6@Q2K}d4U&4G9b&<>=TXPZ_oq}m3fXh`TIJJII53Rg z6i4IW8OgfOB-(m@N%pZUd%*}>ja-Nja3A|c5w0w%{uq}ljM$-|=xqFsOUc(~+lJNHSW3==iG!|0?)bi?=E4;4mlr#koC3xq(WrzJmFDpezGIapqf=ruiKttnqD*uO*D>IUni*@ z^al-z2CDV~8LAFY4n=;vUglk;^A##5X9VAtl=j0%ABeL-Y7ptQLU*Sn3^nXfImA-a zrQtN-IxL%B-dXCOosm&AjlPxKN4W6fr7W$i2I}IQ6y$}U&7KP&%O2@7P{l1*aB`bo}2b$9sx>g>7 z4a-nQ*JNQ?FMUCGS>T=u`##!0JIu1vNb0IW@WvUbFL0V^YBOZYx_THXnu9Mr+V8@G57%OC%NrrEy;o$UW_`>W!dRvLdx*)D=?QVOui6oB^Gt3hz4bfh(h?U%Z z{(>%z&>XZeYB?^nx+yj0WB5(ROcaXc+9n9dVjY)K9YCYW5jbW!FFc;G~+%-u54|z zw7lOsJ9Wa-QNw8GVQg!2#Jyg~wW%Wz&OyaqaG9^%$<&*KV(Y1sViN$A zaIV>ew81qcYA`=hR9BBXs@_ z7>b&Vl!1dAKihUaOueizfacVo2FQUmeux%_*(;zDK zvm#rR^FsRu2I9+`Hoes$pfX;jjT;{yjhwynGBPd72OmKOJo~Bzn6|L-p>8=?e2W0y z%F058l;=KJ#Se3Fa7bnD3K>Z=)VWREzYxmuwxt;xs+PQK(| zI?oi@wd6!;$+u`VC#%EfEoVrxa}#ZlQ#&WlA3{-}qKD2wyi`Xs!LoV%2 zUphNkDy21cv9f+BE|y#xzILaWUgf>g+SjNRspKNI$-5o_#0%$Ab$`OsgEe8PogzSWGAWc|p&@s-72x%X83 z*c(-V`I+x_@4i-%cpX1QbagmrUD#S1pJo(mk@K#mOPc-I(aLMVMaseLToPaZ!GmrT zBeOK`9dc+3u`>{94>tSU1utx%;MJ5v@1(f}F~`So4L9hZZzfGaYq8`l4!O{31ui*b zhpH{w;;C)u!9r180bENIA-;4}s#iL9x!-bX34LOX}IxVVbiOY9=4Afv{YyQ`2~jt4e>gQZ(|3Z^70Bf`D*v8c1(R48AVWA z5P4xwf=tF}gTBxX&EJc)s`mWMLVO;)b39((oixj1c8cfzGv4%A|2BI~@EY*fC(ZGx zA6H%qMxRr84)r_)J*VSOno};EreO1{_)M?WR2(Ui;zWKkR$DC-A1|-ATNz3VJ$UqB zWaoMB9z562g!6Dt&dlH#gf9KXT9drNgcd2>aA?7N?OFtonhr!G@))WWNRoXH*6Q}v zbmQ1u1@hynRi$_0PQFJTE3zTe4XVYnlS$5SVu+oUxJmL)^{n~kYlu`^iIXQmzXtC` zvg4DZyooC2IwkO`T0k^(3@32K{YQ>up(UX}6aKQ&LdowTg4Q@q6HRRSOW~Jx@ke1< z&`bc;V_qXZZ&?c<&fkFY#3t-FZ9b&3+Z+=3e>b_)mMWTPKz)5{!K#h;&LRp>aCCNR z6uk>lzP+V=?;5prwHMrDS!3FolbMsFemvW_MPGK{T-=0RL$c0@K1vffbLdutnXv4( zUc_rzL$;6WVG^;)#xpB&;Od;_^E$8smNOpgxp&IJ9_4cpQ;9OMoua=Bp$PxlQFcefM>8yPdKxsO{HM3QxN);9kvy)Insv4BfzaU~_ z>6XyxA^-B}A>zm(I<1rD#C_UumeOslSwomZU^1ek>4!B8R>|kt9)VGUp6`5GbvuF^ zMpTd&`xEh0(bwstoq@*nLg&n9(FR9vGaeCD0wI1 zXT*^g3nxb$uaj_0xr#UlO91g)0qo;3 z{#+_gXW8o0u<*bZDcN_to*qv11WH=VpWqnt@+DzD0x&1b1VT03#zq)?5{HiE_fN2! z;WBNx6t43X{W;nXOuSg-!;D8H^E?4~+Su6iMLZ$iclxN*77PFy@*J~s{0Ol0*vdLx zot8StCcyEB83pSou!n!+oa_)a?4Fw({stkNTe~9T(?ep9p-wtGdw`E>KdK%r(fOXb z^n0tIo%X!4DIT^k3_Essn0h9J`p0zj_Qqy6%BSaL&VdR`pBCun$GR5IbDeF7H9Fs% zH7)|aCy^dIJuO9~$G$RA^VvnDA$Axz@_S@OYDBjtDmv~0m;hQf2pS*Z0Fmm6}t6$Xud*z5UHA@ZbcRV4amN ze#%()L?4*qkFCe0q?ya4CF|h+{V!2;Da4N8njYYxBnB6 z>pgxszB~c6`&jBUX}r zCx36z7ap*5nO)C1lip2^XD9GLgiGw$5%TDfcIVor%8`D<>{BIgrC|PWwSC(mN2e7H?YG- z>@8>Hc#52xW@qo@G>;i3s5@trlvozvx&s*Cbov4!bbBv`X7THm1zS!CBB@x zbTO4nHCJ2eI(jg6<78()Y}H$XQxV?Sb_Sr2<2E%E%7S5GX^+ymc?hd8O+E^GS72MZ z8RVI2!YfNU90l9lB_~k)jK;z+ePaPU;9a_C3P3<4P|@*1OqQX9=IBFy<_VSa=r9x& zGe4IX7n5lH{QT@49Msw#Sc~l3`Q@3vCda;g%KqEZxGG}DFDpf~HXcPj?m3G%@@+2$ zp*nk-#6qL`0dL1rR3dW)5b)0GBIK6n=YMR05ecp<7-zR!U9s9s z8&f55X_6gJzq(kZ7Tk%o+9+R7xD4A28VkF(eKb_gnkWWYVdGVMJAN@9Fa2%)3> z0QoQ4hVjp5BqiM(dE6JFP+qf|2tAcY&8`_85n<}r#NzJ-bi$G}FvCjDPR_|-`09B1Hdn{)L)DHQt z&7h*c^d0K;>#eR_*+1=+Q3u5kcJ+=S%!8X)_pCO!h688Zs6j-gmt5D?arg_c(C&u3}^nCR0ZU(=n@t*l=Xv40CsvHQuRXa+Yg#{?)iRX zy<$9N0sMaN7z&{b50cX1nd4Y^(Uu$7c)9cVAxUF$6G9?Bk(fiiFj0l6C>tg6-qOWsft@>2_ZJVHGN2OgEPJT==rj;9AkSi5A)> zl!rg@TT)I^R^$vV)$iY)Zem2ng+Fypcl`2?{0Wa1dUB0wG~40l_3W<8#8UF+7kh@q zP0k$1b7q~v=OF8^28`cWuJd6A*K+&0f#x`jgq{-aw^t@+GZsE4{GBhKwNE`)O0MtV z;E?d;()+Z$hp1F5l$c062pDk#l}%H5-$B={*LJU-O>uY!6fNUEt0#^={73oco721O zs&X%~n?@k07O#7^y?i^~DzQe!6?HpLjCkg4R%jtqJ*oYDOivFHeGB&v=dw8T1}^8$ z2Xd~dpvf6+NW0hRvBkyDes1wd49UHP->s+%g!bv7*Uv+KRe?*;TP#lW@T&j~i=k6m z7Ehq>7hTHz<4(I(rfSt&(F_? z2NcLJS)aPLHv)sBJ7}l~hBbCKRJpxl>YFiha`*6f6bShV9BQoWpe{XsK7hZkyW2k? zAf_qq)f_e;V7thKKm8H`putlw_=-cwrO%)ZoQM^bGD_|cSamYn7uY3KCPC|x=gtHe z=Q28K=3TRc_Y}wr#t0kx15}!q2g%i6&y6)sAMzjiATzZoY)!>XpN`(N5DSsIDbgfhw(M+_x$ zZX2~bmzA-)hZB=QSZ!QPQ4jS`xz{14lb4!W)6~>7eN~ob%N9F(drjB{cXetRkio>^ zZ6kW2&>%~-naj|TGheYH5HVsN*?NL=PlR_WSC8s13QFs|OAM*4u&^5=FV@BPm1q=x z^Tv&l(b2wPXEw^nf;iXn<1wzh25c@hd`r4f{m1F6&b)ctQ)noS{VKvmwfv-K5JQH> z8!HDYikQ;H<5JxyF-~Im-%V5RO1h0YT`;~=%D6g7C}d_z`&h|uA~216S1zz8U< zyBv*K2b&X^Av&##XQGv%gk!?rk}jx~p)gYRFS>>r26lY(AVY$a*ivo~td#y4Q|9sQ zJ-cDZCLr)?NrWxWY8`m9VoPmGl@nt^>aLqR#xMnnx^g|Td#bt+gCNUH~d;v zjBLx37(f{_ArBsW>FMd|BiQG1|FJMXPF~g>-{$lC^bI+&f&h*FX#%HmE2(-g6{qg@OmhPXQT}G4mn6xyAxK?`s-2nVj!p%*JUMf z9pf|V1v7AQz;+RXbM?~gs)~X`VpRG^F%MN_EP$(|ky|?^W^&TfrDbJYTwKgCE)P!8 zNbD&sFKo|4uJb#6!sfnM=IY{M5EfK1ZQ2!1Q$5vBJb}a4&vKXE*Rrd z*f)pZL(H)pfBZe4|L56)q98*5`D_BHqzr4t_%PY;>F!p}&(CwH5KgyRnNuF!=ClWc zEt~{>pOe0UdtH~H(e&l=3_x`GK;F*ls~E3XT88YucpS=@WqCh7Fp#5O6^QRR8zCz= zn7xju1gL^iQ3r#j-~^|ba?S<*y8!_K>1|Hgh|B<10&TwG=MVUyucs&T%GcwoXR+hS zgQ)}ny3eDXd*&1hDD09{VxjA|?ccd;*F~_}&Yc5c-E{2b#cJ0k5Pobyw6sq((+SFr(_o?mZI|{>y`}rC?hLe}~EHT!C&9;@ots~A}ce0rOXl^wfrL3*V z7@z_6VD2`9GeT1hNWuVFEz>VmJ3-Kop;@F3G!pQI4H$bODi}9$ zZ0bzzKV+ff=r2Gk+kTsWX8yZrY2;|Q)3gD2F&HIkpH92^xGC^Arn;AfMaAvz?>=5O zp4+HRfo_&40{W!Wb==Awm>K?ByVj?E_cxz_0R7fv$3hwL;+SyIn$Wq7A)TJu>NZ&9 zXoQuOl<3lQPo|G18yHCVWn^W=u2nlh(>?v?()r{a`w8O>7L6hq3yTqqSIZ(Y9J3xU zK`0Es3G5&Q8zgX*Ra7v6EQ7*>xwk0a+YSw6WP&J$CT`-aDxI)!fq|)>Hd^fi-hHUm zAfBoDU^R0=C!0J+1H%N&nlo;(naEYYGJ8htt@>;joI~h6(ApazyQE|UFQ=YsU(4p+ zG*PInM&^`e1w{GCGwkqHg3xK`Y$=oil_D&deIGr7t*;>r{m<>b1QrLJ8cp724wlyB zMMKVc4Fb+u5L0yAtTSl$X>vWWfg>{fAPyfsoP5Ksl+5sAoT1W0whJ!TJPxh?tn7>S~24ne+1?()y_@ z*Rwehjd&)kKBv#1>hQLs0fB!9GM}>YrURo*&lP|C==YaN_=WPttD(rPni>P}ebd*n z&5uY-#KiZF48hCwy{HJnYIst4jWiW1p7Et;^FmEM=j9GFt) zZ!j8m=hiJYn`j~XvF{LS>8BK6DvB2WvvFxmXXC#7vDUvM>X@&?DHjQw+VAiFjY5FW zOx7R7&b=jS5%b;mtrH_gs20I4P(5Ofzj`FEkOreht$H?7(V_nSIHy5wkYv#NtM^r( zg2S1O1{g--Po8v(gNzR%xL^SjUgto8cotUHj{yfx=!Q8>!**7= zDQ-_iRhRXspXdBS(X~f1s?xHuzDy9MYjDOlEPS|S+HE2(_MxG&@*$=~zgS0)*Yx<5 zefj#;9PVjWZe@@xt4*C$J^P-REZG`wCOzt8WlsV(t5@*dDL{|L#+aO{zk&!F$Yngw z!}EDS5_(*WE2WsYOqB(9Dq&ygttrlP|)JfA~1lzi= z-9U6_Rw&(3+m|Db{ox*>uJv0M>9?c)2Gy$nuEPZS;HEp+n%fk$BErwA_K1{td?<1- z;Pf~Th6i>d;AncSK|C!VIfGkM^t`6Ew)HY>1eQZIRO{U+v?NvWEvlIoIxx#CC*mZ4 z8cXTo>paa70vzPJb{R2bB+n;3+bmq-z zUO?P*urM$wgu!XDE)3`F@bT-rl;6NA7}IWMJ_toY9OiU9pLFTe>C<=D`I9gAhMPJn ztK1oe^866^2dO{^1n6XZ=C_$h+jQQ#wVdvNib`t)ng}cuag~H7I+a7vPOD@-etZFv zoV5AETO6=)*SsNFn#E1ru>dmFleOLEjwIWlYW!JLjtt5m-A9gFjgEzaWb3pcl{8?) zng8E7wxsppUwmCN7E(wb6R{qM0|IjH#)S{YKdZw2wtVMLkB>nsz3D@$+wrQqFJ8PD zY$;6}UBo-guUvsm_Nz>vOj2F)g2>BAS;?F~v1$2ug5w@6lz^O!ih_bpKrG7nJ0F|0 zU1DPPE43}LPD@wXy2+8{tMp9h5i6)08*}VZ?6T@w{7Bs_edwyL1o(kJ^Qbk3uPOsX zRmkm^pEB74WTiGgIkTXtNzFSN+tc+FAima&EkhM+d*b=q;Ul$R`uXJ(T!bAg{}Y$j ze?pL*-2m)W0^{5||DFj>iA0O7{{~4`2sP;&eh=~v#ytK@mJ`()6_w!x^st1dX>4pS zTDE(%+(Ck7n!@z3m2S*)6uP;Z!u6)A;bCFX!8L=#9KJnZIPRZb){7}P@Ehhj_c=EV`vG$62mhfyfmK~y9YZvvXeEkh zkJNumZA#Nh_(*hMEiH3k>3}hCNqI@eBEO!(K<0PjNCll1A2soO(pxE-^t>D8Z{dbI zGd;}%#yVU+;7>^m=+o0Ds6}TlEHvZjUbkJKEK)WJ9HZ5vX{Hmn9=I2@9LH<57N+YT zKi=8E@38ju;t^oxN1?7gzOD2G06KiG*D)TQye~eCc`CT7=Vv}`H_I7z6`g%EpNS&} z3y;+VptDqXt$e1@9KYrPn32H0JS=y`m&NlJ9xO!|pTQ!Eoez3u5UFf<+%Z-Kb<>b( z8vIhQqzA%-eSG*JO7;<8d2OVSTfjDtng#&Z@cm^J-r(bhvLS~Ku(M0*BFZdUCeR|7 z)Z8Ih40XztfyRRa(-6+(F3iu=cK>Sx3h9NoT5)+fqSfQdxhSkevC^31XzD$FcfBvp6_-JHfzt9esC76^a#K?koo2r=E!YZ? z)ZgY{X@Q&`J$oRH5&QqR+p5f0nRnvCVVl;11Tzez@NCd`lHqIkIX~qx^nq) zf;M|A3^y=(+JTei!(c^tg1*<#kcmOA_lr)6h;CL^R>+fl1WG+k|BB954>hY#2t}X@ zMji+kk+9zK^D|SpyRR7%k3ZAubUrZb^}MA}{j*P@*pi>?mBI+U5*_<#yi{q0vqosw zVNFJa^NOMso$2$FKHY7+))+aP>GTgq^|96{S48ic{SPt$~a7$UqIZ?W$R!S39{BeTeZ6*E#M*>=4y zWr}mYplIloWYjpfK>eZqF!eqm)uJzGTZmoHrUZcLDI*)*_eay~?9NN2lOpk=Vl-yE z7Vq62ht47vub)7aWH@GEX}zbiX_{pFQF9)8eDpD zR6jokMcF`MfPfyp1IC8`L5!6|0^|QzVr*pQ{bJz>{wKoG$;nj}6^U@7>B(`ox9K4} z)b8BZYfaD2!9g!*st(9&)w*pjvAL{dY6884;GiZn#t{|n@n z-!F)A~NgPc0Wa zT8=u+W>kt8v@x}q1X|8R83rO%J~9s0J-6P7cIB6fBRH%OXYB@G`(v1gY%zO8uyFR6oVLN=uO%vLA zo_+f&ii_!BUSpcl>jgVL%lR4kTzf--$L&Tu26&EI~8ZFjc?0#>jnr)~sx7Y^XXI7wnc}lYpnoeo{`I zo#dHDvz^kXUl<)pTS!PdBa&4UB0{DRfn^J| zzG`5-lWIa!;36#Cl(>#^y%tte?!%-_KWQtzSJL20h5vs=)01^klFlBlo@HCWw8RSk;!^0Qz+ zmabwl^K+0oxB}9f=Dp4KG=f7_zelg(4 z+`+^YzLF^rQ1pN8HY{zn?W$DXl$Y9u)(?XuG`GRgMlB|ER!)S0+<0zIj`jk{Ov03Zj%>gV zX_z7Y^ODW%IM7*z#98KSmg<2XlvTRfY8&NFrdOf~E1r3m-FL+6d_B8r?jg+~-lzTg zyKYka1hCn%3ntdnU>JM(`&h@!9st`Ee?tJA_p?vVJvjPY_H(0LB~c*|9tZU}a9&d2 z>cx2~rhHJi5S{n<`?>4A2Uxe<)?3p$)!$fP@nH=GYG1VoOyBwwLDky_plA_rC5YXW zqUsO8b;Ez)xBrv#0p1ZZ`P?ZT|36Ag8~73uguLJIu93~arKwB}Ex{sYhhmdgR|cv& zX$82_`B-K3_+8FDTk_(PLV#&Lui$Mr`@i@TZ&(X*QjcF}NGp)%{-)TVmOMAo@(oInGgo5HT2_4`eS6u`#$e=ufHf(pF_5Wpc4xb z-QM2I_F!Ju?I;NTs86N7alg4W74dHH?hhtj4rkMJT{1T&zmNpp)T2i3Nc169v_ zg4OEv!UAnaw6l_DtDXr1xVn|?FmazD^l8M2bmOT{B`NgUyls}b(RYrhoT0wns6$J`z_DX_tg^LPzC!lz%}r2kbCa$OG@hDhbuc?yrFFMm>_wKvK~b_SW2lJZ zTLt;Kk?)n`7P9OMc@wRrB+|`Cu8a;`_N_T>VWRm8ABPvlwHE%SrPc0KSGHzMgFcRX40=uI*Qnm};P99`)wNaYy|gfiDL!F-B(2^_ne?#Ox%TgZ zKFetz_FZ4c=jR-c9?dE(ctr*mSK@x$_Jh5Q7Zp62_xoJD+$*+jE$e-=kn`7>k z_CI@eJ~obZeaXY!eW&G9nc~|g=lx~ zlH(Rj$*?$hm|V`}I~p>`E*luhI@_xpp&g2LWpJc3mo_}@a-qa#Ru4Az2G(fKKrl4| zC2J4HR)`0`I$yCcKVcIY_uQ)_^Xj`hHYOi;0$0)!U9hutnxAfO=k9&EE$!#Ut@IM0 z4y@T7vF5V#Lv|ynFC?b90W+rZQt5UzzW$gjyZ74uYI(B<4{zQ=Yx?NWT>HIzNW7OU zaXc44ozm}T(dgZrATsuLZ9bwq{e3GKBs~67k~6VzVQZ7~mnf%R<>O~0+zv_7XAckg z*x2Oi>V>wg-wN-0o^fhU?mSWaqQvm>hoiFvTZgx73GA!SZ^@lmM!pHH*x`jhJyz8m z#r?g8_c8_alSt~VnWFRNK^~9DmDiUoyU!r~kWOWAuvKFwt~xsXRlvTOaG~@F#0=Kf zYL(>dU>uRE2y01jOe#6SE4gKx$gJKu#`c<}{ByDTPFSkF-))@@4DL+nJPX;08;~u! zslR_YX9c~0@k@IfxDk2<8fBbyRZnlcvZLd+lT%o<+%saZZgpgCd}t^__*=lq z;hU@K*+#t?)2JnZs-}_ufPHqD^f570GXw8Yo zZt4{QdelCu+KLzZIg9TzFiGlu63KF!Yg)E)(lBMs_;nCjc=qb;7;v1Id74pqj`JtW<(j3<%n`wR^3xvpEyJ8iLX z{7J32xsL`$f#=EEI(b>srS>PyJI(x02RCM?dG4SS&_DA9{e4u^Bl4B~hM97!-*!l> zZc5B03l%pdlLn5ATzXc~*!C%bSRI;1b@eOD54q>#Xv2oLT_A^Z%Ma`n4igEJ4HeVH zR!^)$HL~XwW;(Bj3W+ib3AE1)38sEw%QLJEcODHsAADOO%7e7P9F_A~FWhnVy_>AX zgQMj0uz4tMG~aK3S7Gg^_b;AKC21MyJm|sQDHp^KdxevSwZe`Dh6PM^y`vV5(L8dE z+@K{T^=j_Ny9DQ%bm!W6r$@ypkxNTY=vA2dE6hZAi8swI4UpCI=uN4N>Qk)Px-YCL zGiB73>0`BqNvR(-#xwVKsO(jHNUz^2GQLrNcRe2?V~e1Py;cGh%dS-`$(4*Xx%QdQ zB4?F6nOM_`V&2BYD=FznJI>TQJHG!OaSyk_cHHk-f>%*HG_si{ml6jLpRP=XrGdQD zyuDovgdpgxlDkVcjW68Mo}T=+z%Bhq%l4H@TNf^JgVc?en+hP<#0hxT?z&N34$Iow z>X@8f44TvAF6$&0&|al1JQ-=f9NsGzUe8UW`&-O5U(HXJ^nKfuUEfvCq#r&qk)OXu zJ}J{iOWM8t;>BYE&hNyg3f2vTmw0$-eHm&KVrITlc;Cy|S|NgRFXj;UV%oWtI;#2e z1K|rt)j!G*$6&#}r#1V+&04aUj~uBfE`EYFJoSw!y5X8m>35Y96H@1Hv9M=zFQUbj zl+#6mjj<&C_116uVl);i7TBRKq+9k*Q!_VpLGVe_&ui%|-oY!+vsA*<{`6T-@*(W= z^oM!Nx;FG?Q7&cMF)Pa)EuLwX;{n$a0>b8x8TX%=$>))C)Mp{7Pqcm!&km9Co@;K& zE^VEe>b|Gb_CkUt-`*;mKOt8`1(nD$YRhxZtC~7~Uq@os5KK?lRNiXeS8(`h)bwPA zTIS6xU+LSlb|#;4B5YsGl_sV0ak0*L7KnNlJzw#dgO^0T1V#6ChH>ktzWS>u`>wE> zloyInO4C&tJ1?}K-A+`nR|;)vBpBVA^X4K-O5%coLeg99%~8r(utG!>;YLtCIh9#? z(ufyZVsk}816TIg&7}+sLldK;*9Ows3>MCff^_4t2Z8f%2J zef-xu^yS-!7q}!vvkHZ^eADydWlRxDBQ3HqlVSFFFB|6F3& z$e$;?Vp26wU}0PoZ3#KrdD`oi{{mNH{NGWNw^+~01iydDABgAsMk)RI@`{O<7s7Nc zw`qf#59*L+uKlS9?+vE~Bl&=GtdmyQzW%Y2!EU9$Yfcbd!3BvGz4rZr(QIMC!Px-z z(aG3Ja&C7sRz0$_<-tb+&G4m`-n@f&(waY?WKKK@9Hn6}V2kfbN=vI%pVqFfTGDgJ zvI}#X_-p5bzUWiMODV*-KW1D?bT&d9XS^=wA3imV0Y_;m2>0b^%qo99DGHt0|MHu7 z_I<&tj!1#s=OwtQA=OeWYgg#=gap&hcU8+Jmgy@69amcZ>&v)qzhh?N%1MkQsi>|9 rg4#p;0CF?&zyHPz5P$o+W?@CrT5cu@S4|G$QIeApp:Start Login +note right +For all intents AACSCoreService<->App + +Category is com.amazon.aacs.aasb.Authorization +Action Prefix is com.amazon.aacs.aasb +Payload is JSON AASB for Authorization Interface +Refer AASB Message Documentation +end note +App->AACSCoreService:Intent-Action: StartAuthorization, for CBL +note right +Payload from Intent is sent as +JSON AASB Message to AutoSDK +end note +AACSCoreService->AutoSDK: StartAuthorization, service: alexa-cbl +opt +AutoSDK->AACSCoreService:AuthorizationStateChanged, service: \nUNAUTHORIZED +AACSCoreService->App: Intent-Action: AuthorizationStateChanged +end +AutoSDK->AACSCoreService:AuthorizationStateChanged, service: alexa-cbl\nAUTHORIZING +AACSCoreService->App:Intent-Action: AuthorizationStateChanged +AutoSDK->LoginWithAmazonService:Authorize and request CBL +LoginWithAmazonService->AutoSDK: CBL Code and url from LoginWithAmazon +AutoSDK->AACSCoreService:EventReceived, service: alexa-cbl\ntype:cbl-code, payload:code and url +AACSCoreService->App: Intent-Action: EventReceived +note left +App displays code +and url to user. User +authenticates code +via LoginWithAmazon +end note +AutoSDK->LoginWithAmazonService: poll for tokens +LoginWithAmazonService->AutoSDK:refresh-token, access-token received +AutoSDK->AACSCoreService:SetAuthorizationData, service: alexa-cbl\npayload: refreshtoken +AACSCoreService->App:Intent-Action: SetAuthorizationData +AutoSDK->AACSCoreService:GetAuthorizationData, service: alexa-cbl +AACSCoreService->App:Intent-Action: GetAuthorizationData +App->AACSCoreService:Intent-Action: GetAuthorizationData, stored refreshtoken +AACSCoreService->AutoSDK:GetAuthorizationData, service: alexa-cbl\npayload:refreshtoken +opt When user profile is configured in AACS +AutoSDK->AACSCoreService:EventReceived, service: alexa-cbl\ntype: user-profile, payload: name, email +AACSCoreService->App:Intent-Action: EventReceived +end +AutoSDK->AACSCoreService:AuthorizationStateChanged, service: alexa-cbl\nAUTHORIZED +AACSCoreService->App:Intent-Action: AuthorizationStateChanged +@enduml diff --git a/platforms/android/alexa-auto-client-service/assets/APCP.png b/aacs/android/assets/APCP.png similarity index 100% rename from platforms/android/alexa-auto-client-service/assets/APCP.png rename to aacs/android/assets/APCP.png diff --git a/aacs/android/assets/config.json b/aacs/android/assets/config.json new file mode 100644 index 000000000..b6b4adf1f --- /dev/null +++ b/aacs/android/assets/config.json @@ -0,0 +1,105 @@ +{ + "aacs.alexa": { + "deviceInfo": { + "clientId": "", + "productId": "", + "deviceSerialNumber": "", + "manufacturerName": "name", + "description": "description" + }, + "localMediaSource": { + "types": [] + }, + "audio": { + "audioOutputType.music": { + "ducking":{ + "enabled": true + } + } + }, + "requestMediaPlayback": { + "mediaResumeThreshold": 50000 + } + }, + "aacs.vehicle": { + "info": { + "make": "Amazon", + "model": "AACE", + "year": "2020", + "trim": "aac", + "geography": "US", + "version": "1.2.3", + "os": "Sample OS 1.0", + "arch": "Sample Arch 1.0", + "language": "en-US", + "microphone": "SingleArray", + "countries": "US,GB,IE,CA,DE,AT,IN,JP,AU,NZ,FR", + "vehicleIdentifier": "Sample Identifier ABC" + }, + "operatingCountry": "US" + }, + "aacs.cbl": { + "enableUserProfile": false + }, + "aacs.carControl": { + "endpoints":[], + "zones":[] + }, + "aacs.general" : { + "version": "1.0", + "persistentSystemService": false, + "startServiceOnBootEnabled": true, + "ipc": { + "cacheCapacity": 20 + } + }, + "aacs.defaultPlatformHandlers": { + "useDefaultLocationProvider": true, + "useDefaultNetworkInfoProvider": true, + "useDefaultExternalMediaAdapter": true, + "useDefaultPropertyManager": true, + "audioInput": { + "audioType": { + "VOICE": { + "useDefault": true, + "audioSource": "MediaRecorder.AudioSource.MIC", + "handleAudioFocus" : true, + "externalSource": { + "type": "", + "package": "", + "class": "" + } + }, + "COMMUNICATION": { + "useDefault": true, + "audioSource": "MediaRecorder.AudioSource.MIC" + } + } + }, + "audioOutput": { + "audioType": { + "TTS": { + "useDefault": true + }, + "ALARM": { + "useDefault": true + }, + "MUSIC": { + "useDefault": false + }, + "NOTIFICATION": { + "useDefault": true + }, + "EARCON": { + "useDefault": true + }, + "RINGTONE": { + "useDefault": true + }, + "COMMUNICATION": { + "useDefault": true + } + } + } + } +} diff --git a/platforms/android/alexa-auto-client-service/commonutils/.gitignore b/aacs/android/common/commonutils/.gitignore similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/.gitignore rename to aacs/android/common/commonutils/.gitignore diff --git a/platforms/android/alexa-auto-client-service/commonutils/README.md b/aacs/android/common/commonutils/README.md similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/README.md rename to aacs/android/common/commonutils/README.md diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/.gitignore b/aacs/android/common/commonutils/aacscommonutils/.gitignore similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/.gitignore rename to aacs/android/common/commonutils/aacscommonutils/.gitignore diff --git a/aacs/android/common/commonutils/aacscommonutils/build.gradle b/aacs/android/common/commonutils/aacscommonutils/build.gradle new file mode 100644 index 000000000..6f52aa16f --- /dev/null +++ b/aacs/android/common/commonutils/aacscommonutils/build.gradle @@ -0,0 +1,45 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-kapt' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 26 + versionCode 1 + versionName "4.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation project(':aacsconstants') + implementation project(':aacsipc') + + implementation deps.kotlin_stdlib + implementation deps.androidx_annotation + + // JSON Parsing + kapt deps.moshi_codegen + implementation deps.moshi + + testImplementation deps.junit + testImplementation deps.mockito + testImplementation deps.roboelectric +} diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/consumer-rules.pro b/aacs/android/common/commonutils/aacscommonutils/consumer-rules.pro similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/consumer-rules.pro rename to aacs/android/common/commonutils/aacscommonutils/consumer-rules.pro diff --git a/platforms/android/app-components/alexa-auto-tts/aacstts/proguard-rules.pro b/aacs/android/common/commonutils/aacscommonutils/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-tts/aacstts/proguard-rules.pro rename to aacs/android/common/commonutils/aacscommonutils/proguard-rules.pro diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/AndroidManifest.xml b/aacs/android/common/commonutils/aacscommonutils/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/AndroidManifest.xml rename to aacs/android/common/commonutils/aacscommonutils/src/main/AndroidManifest.xml diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSComponentRegistryUtil.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSComponentRegistryUtil.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSComponentRegistryUtil.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSComponentRegistryUtil.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessage.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessage.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessage.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessage.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java similarity index 98% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java index dd38af207..11cafd0c8 100644 --- a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java +++ b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilder.java @@ -114,7 +114,7 @@ public static Optional buildReplyMessage( try { String aasbMessage = "{\n" + " \"header\" : {\n" - + " \"version\" : \"3.3\",\n" + + " \"version\" : \"4.0\",\n" + " \"messageType\" : \"Reply\",\n" + " \"id\" : \"" + uniqueID + "\",\n" + " \"messageDescription\" : {\n" @@ -172,7 +172,7 @@ public static Optional buildMessageReturnID( try { String aasbMessage = "{\n" + " \"header\" : {\n" - + " \"version\" : \"3.3\",\n" + + " \"version\" : \"4.0\",\n" + " \"messageType\" : \"Publish\",\n" + " \"id\" : \"" + uniqueID + "\",\n" + " \"messageDescription\" : {\n" diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageSender.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageSender.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageSender.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSMessageSender.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSReplyMessage.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSReplyMessage.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSReplyMessage.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/AACSReplyMessage.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessages.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessages.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessages.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessages.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessages.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessages.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchCommon.kt b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchCommon.kt similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchCommon.kt rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchCommon.kt diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchDetailTemplate.kt b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchDetailTemplate.kt similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchDetailTemplate.kt rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchDetailTemplate.kt diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchListTemplate.kt b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchListTemplate.kt similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchListTemplate.kt rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/LocalSearchListTemplate.kt diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/NavigationMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/NavigationMessages.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/NavigationMessages.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/NavigationMessages.java diff --git a/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessages.java new file mode 100644 index 000000000..c0da0eb28 --- /dev/null +++ b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessages.java @@ -0,0 +1,108 @@ +package com.amazon.alexa.auto.aacs.common; + +import android.os.SystemClock; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.amazon.aacsconstants.Action; +import com.amazon.aacsconstants.PlaybackConstants; +import com.amazon.aacsconstants.Topic; + +import org.json.JSONException; +import org.json.JSONStringer; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; + +/** + * Parse music domain messages and send music domain messages to AACS + * with this helper. + */ +public class PlaybackControlMessages { + private static final String TAG = PlaybackControlMessages.class.getSimpleName(); + + @NonNull + private AACSMessageSender mAACSSender; + + public PlaybackControlMessages(@NonNull AACSMessageSender aacsSender) { + mAACSSender = aacsSender; + } + + /** + * Send Playback control Toggle command to AACS. + * + * @param toggle Toggle command to send. Must be one of the + * PlaybackConstants.ToggleButton constants. + * @param selected Whether or not toggle is selected. + * + * @return Future with status of send (true if send succeeded). + */ + public Future sendToggleCommandToAACS(@NonNull String toggle, boolean selected) { + Log.d(TAG, "Sending toggle command: " + toggle + " selected: " + selected); + try { + String payload = new JSONStringer() + .object() + .key(PlaybackConstants.TOGGLE) + .value(toggle) + .key(PlaybackConstants.ACTION) + .value(selected) + .endObject() + .toString(); + + return mAACSSender.sendMessage( + Topic.PLAYBACK_CONTROLLER, Action.PlaybackController.TOGGLE_PRESSED, payload); + } catch (JSONException exception) { + Log.w(TAG, "Failed to send toggle command: " + toggle + ". Error: " + exception); + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(exception); + return future; + } + } + + /** + * Send Playback control Button command to AACS. + * + * @param command Button command to send. Must be one of the + * PlaybackConstants.PlaybackButton constants. + * + * @return Future with status of send (true if send succeeded). + */ + public Future sendButtonCommandToAACS(@NonNull String command) { + Log.d(TAG, "Sending playback control button command: " + command); + try { + String payload = + new JSONStringer().object().key(PlaybackConstants.BUTTON).value(command).endObject().toString(); + + return mAACSSender.sendMessage( + Topic.PLAYBACK_CONTROLLER, Action.PlaybackController.BUTTON_PRESSED, payload); + } catch (JSONException exception) { + Log.w(TAG, "Failed to send button command: " + command + ". Error: " + exception); + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(exception); + return future; + } + } + + public Future sendRequestMediaPlaybackToAACS() { + Log.d(TAG, "Sending request media playback AASB message"); + try { + String payload = new JSONStringer() + .object() + .key(PlaybackConstants.RequestMediaPlayback.INVOCATION_REASON) + .value(PlaybackConstants.RequestMediaPlayback.REASON_AUTOMOTIVE_STARTUP) + .key(PlaybackConstants.RequestMediaPlayback.ELAPSED_BOOT_TIME) + .value(SystemClock.elapsedRealtime()) + .endObject() + .toString(); + + return mAACSSender.sendMessage( + Topic.MEDIA_PLAYBACK_REQUESTER, Action.MediaPlaybackRequestor.REQUEST_MEDIA_PLAYBACK, payload); + } catch (JSONException exception) { + Log.w(TAG, "Failed to send button command: Error: " + exception); + CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(exception); + return future; + } + } +} diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt similarity index 87% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt index 17d630437..ef44547d8 100644 --- a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt +++ b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/RenderPlayerInfo.kt @@ -47,7 +47,7 @@ data class PlaybackControl ( @JsonClass(generateAdapter = true) data class RenderPlayerInfoPayload ( val content : RenderPlayerContent, - val controls : List + val controls : List? ) @JsonClass(generateAdapter = true) @@ -58,8 +58,8 @@ data class RenderPlayerInfo ( val focusState : String ) { fun isControlEnabled(controlName: String) : Boolean = - payload.controls.firstOrNull() { it.name.equals(controlName) }?.enabled ?: false + payload.controls?.firstOrNull() { it.name.equals(controlName) }?.enabled ?: false fun getControl(controlName: String) = - payload.controls.firstOrNull() { it.name.equals(controlName) } + payload.controls?.firstOrNull() { it.name.equals(controlName) } } \ No newline at end of file diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessages.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessages.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessages.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/StartNavigation.kt b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/StartNavigation.kt similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/StartNavigation.kt rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/StartNavigation.kt diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessages.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessages.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessages.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WakewordDetectedMessages.java b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WakewordDetectedMessages.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WakewordDetectedMessages.java rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WakewordDetectedMessages.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WeatherTemplate.kt b/aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WeatherTemplate.kt similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WeatherTemplate.kt rename to aacs/android/common/commonutils/aacscommonutils/src/main/java/com/amazon/alexa/auto/aacs/common/WeatherTemplate.kt diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilderTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilderTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilderTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageBuilderTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageSenderTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageSenderTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageSenderTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/AACSMessageSenderTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessagesTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessagesTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessagesTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/ConnectionStatusChangedMessagesTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessagesTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessagesTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessagesTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/DialogStateChangedMessagesTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/NavigationMessagesTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/NavigationMessagesTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/NavigationMessagesTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/NavigationMessagesTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessagesTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessagesTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessagesTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/PlaybackControlMessagesTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessagesTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessagesTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessagesTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/SpeechRecognizerMessagesTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessagesTest.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessagesTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessagesTest.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TemplateRuntimeMessagesTest.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TestResourceFileReader.java b/aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TestResourceFileReader.java similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TestResourceFileReader.java rename to aacs/android/common/commonutils/aacscommonutils/src/test/java/com/amazon/alexa/auto/aacs/common/TestResourceFileReader.java diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchDetailTemplateV1.json b/aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchDetailTemplateV1.json similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchDetailTemplateV1.json rename to aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchDetailTemplateV1.json diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchListTemplateV2.json b/aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchListTemplateV2.json similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchListTemplateV2.json rename to aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/LocalSearchListTemplateV2.json diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/StartNavigation.json b/aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/StartNavigation.json similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/StartNavigation.json rename to aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/StartNavigation.json diff --git a/platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/TemplateRuntimePlayerRenderInfo.json b/aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/TemplateRuntimePlayerRenderInfo.json similarity index 100% rename from platforms/android/alexa-auto-client-service/commonutils/aacscommonutils/src/test/resources/aacs/TemplateRuntimePlayerRenderInfo.json rename to aacs/android/common/commonutils/aacscommonutils/src/test/resources/aacs/TemplateRuntimePlayerRenderInfo.json diff --git a/aacs/android/common/commonutils/build.gradle b/aacs/android/common/commonutils/build.gradle new file mode 100644 index 000000000..377d98e97 --- /dev/null +++ b/aacs/android/common/commonutils/build.gradle @@ -0,0 +1,46 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + ext.versions = [ + 'kotlin': '1.4.0', + 'moshi': '1.9.3', + + // Test Dependencies + 'mockito': '3.4.0', + ] + + ext.deps = [ + 'kotlin_stdlib': "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}", + 'androidx_annotation': "androidx.annotation:annotation:1.1.0", + 'moshi': "com.squareup.moshi:moshi:${versions.moshi}", + 'moshi_codegen': "com.squareup.moshi:moshi-kotlin-codegen:${versions.moshi}", + + 'junit': 'junit:junit:4.12', + 'mockito': "org.mockito:mockito-core:${versions.mockito}", + 'roboelectric': 'org.robolectric:robolectric:4.3', + ] + + repositories { + google() + mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${versions.kotlin}" + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/platforms/android/app-components/alexa-auto-contacts/gradle.properties b/aacs/android/common/commonutils/gradle.properties similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/gradle.properties rename to aacs/android/common/commonutils/gradle.properties diff --git a/aacs/android/common/commonutils/settings.gradle b/aacs/android/common/commonutils/settings.gradle new file mode 100644 index 000000000..d163b3c54 --- /dev/null +++ b/aacs/android/common/commonutils/settings.gradle @@ -0,0 +1,7 @@ +rootProject.name='commonutils' +include ':aacscommonutils' +gradle.ext.aacsCommonRoot = '../' +include ':aacsconstants' +project(':aacsconstants').projectDir = new File(gradle.ext.aacsCommonRoot, '/constants/aacsconstants') +include ':aacsipc' +project(':aacsipc').projectDir = new File(gradle.ext.aacsCommonRoot, '/ipc/aacsipc') diff --git a/platforms/android/alexa-auto-client-service/constants/.gitignore b/aacs/android/common/constants/.gitignore similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/.gitignore rename to aacs/android/common/constants/.gitignore diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/.gitignore b/aacs/android/common/constants/aacsconstants/.gitignore similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/.gitignore rename to aacs/android/common/constants/aacsconstants/.gitignore diff --git a/aacs/android/common/constants/aacsconstants/build.gradle b/aacs/android/common/constants/aacsconstants/build.gradle new file mode 100644 index 000000000..a8ba43f39 --- /dev/null +++ b/aacs/android/common/constants/aacsconstants/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 26 + targetSdkVersion 27 + versionCode 1 + versionName "4.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles 'consumer-rules.pro' + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation "androidx.annotation:annotation:1.1.0" + + testImplementation 'junit:junit:4.12' + testImplementation 'org.robolectric:robolectric:4.3' +} diff --git a/platforms/android/app-components/alexa-auto-contacts/aacscontacts/consumer-rules.pro b/aacs/android/common/constants/aacsconstants/consumer-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-contacts/aacscontacts/consumer-rules.pro rename to aacs/android/common/constants/aacsconstants/consumer-rules.pro diff --git a/platforms/android/app-components/alexa-auto-voice-interaction/proguard-rules.pro b/aacs/android/common/constants/aacsconstants/proguard-rules.pro similarity index 100% rename from platforms/android/app-components/alexa-auto-voice-interaction/proguard-rules.pro rename to aacs/android/common/constants/aacsconstants/proguard-rules.pro diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/androidTest/java/com/amazon/aacsconstants/ExampleInstrumentedTest.java b/aacs/android/common/constants/aacsconstants/src/androidTest/java/com/amazon/aacsconstants/ExampleInstrumentedTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/androidTest/java/com/amazon/aacsconstants/ExampleInstrumentedTest.java rename to aacs/android/common/constants/aacsconstants/src/androidTest/java/com/amazon/aacsconstants/ExampleInstrumentedTest.java diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/AndroidManifest.xml b/aacs/android/common/constants/aacsconstants/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/AndroidManifest.xml rename to aacs/android/common/constants/aacsconstants/src/main/AndroidManifest.xml diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java similarity index 87% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java index b051bb9ba..e2beead63 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSConstants.java @@ -59,15 +59,24 @@ public class AACSConstants { public static class IntentAction { public static final String GET_SERVICE_METADATA = "GetServiceMetadata"; public static final String GET_SERVICE_METADATA_REPLY = "GetServiceMetadataReply"; + public static final String ENABLE_SYNC_SYSTEM_PROPERTY_CHANGE = "com.amazon.aacs.syncSystemPropertyChange.enable"; + public static final String DISABLE_SYNC_SYSTEM_PROPERTY_CHANGE = "com.amazon.aacs.syncSystemPropertyChange.disable"; } - public static class IntentCategory { public static final String GET_SERVICE_METADATA = "GetServiceMetadataTopic"; } + public static class IntentCategory { + public static final String GET_SERVICE_METADATA = "GetServiceMetadataTopic"; + public static final String SYNC_SYSTEM_PROPERTY_CHANGE_ENABLEMENT = "com.amazon.aacs.syncSystemPropertyChange"; + } public static class ServiceMetadata { public static final String EXTRA_MODULE_LIST = "extrasModuleList"; public static final String METADATA = "metaData"; } + //AACS State + public enum State { STARTED, WAIT_FOR_LVC_CONFIG, CONFIGURED, ENGINE_INITIALIZED, STOPPED } + public static final String ACTION_STATE_CHANGE = "com.amazon.aacs.service.statechanged"; + // AACS Permission public static final String AACS_PERMISSION = "com.amazon.alexaautoclientservice"; public static final String AACS_PING_PERMISSION = "com.amazon.alexaautoclientservice.ping"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java similarity index 96% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java index 50d744106..c86db37d0 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AACSPropertyConstants.java @@ -26,4 +26,6 @@ public class AACSPropertyConstants { public static final String VERSION = "aace.core.version"; public static final String NETWORK_INTERFACE = "aace.network.networkInterface"; public static final String GEOLOCATION_ENABLED = "aace.geolocation.geolocationEnablement"; + + public static final String PROPERTY = "property"; } diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java similarity index 89% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java index 7cb3ed4e7..4d2892079 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/AASBConstants.java @@ -103,6 +103,7 @@ public static class AlexaClient { public static final String DIALOG_STATE_LISTENING = "LISTENING"; public static final String DIALOG_STATE_THINKING = "THINKING"; public static final String DIALOG_STATE_SPEAKING = "SPEAKING"; + public static final String DIALOG_STATE_EXPECTING = "EXPECTING"; public static final String AUTH_ERROR = "error"; public static final String AUTH_STATE = "state"; @@ -127,6 +128,21 @@ public static class AlexaClient { public static final String AUTH_ERROR_INVALID_CBL_CLIENT_ID = "INVALID_CBL_CLIENT_ID"; } + public static class CustomDomain { + public static final String DIRECTIVE_NAMESPACE = "directiveNamespace"; + public static final String DIRECTIVE_NAME = "directiveName"; + public static final String DIRECTIVE_PAYLOAD = "directivePayload"; + public static final String CORRELATION_TOKEN = "correlationToken"; + public static final String MESSAGE_ID = "messageId"; + public static final String CONTEXT_NAMESPACE = "contextNamespace"; + public static final String CONTEXT = "context"; + public static final String EVENT_NAMESPACE = "eventNamespace"; + public static final String EVENT_NAME = "eventName"; + public static final String EVENT_PAYLOAD = "eventPayload"; + public static final String REQUIRES_CONTEXT = "requiresContext"; + public static final String CUSTOM_CONTEXT = "customContext"; + } + public static class LocationProvider { public static final String COUNTRY = "country"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java similarity index 92% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java index b5a07eb22..0f467dbc5 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Action.java @@ -81,6 +81,14 @@ public static class AlexaConnectivity { public static final String GET_IDENTIFIER = "GetIdentifier"; } + public static class CustomDomain { + public static final String HANDLE_DIRECTIVE = "HandleDirective"; + public static final String CANCEL_DIRECTIVE = "CancelDirective"; + public static final String GET_CONTEXT = "GetContext"; + public static final String SEND_EVENT = "SendEvent"; + public static final String REPORT_DIRECTIVE_HANDLING_RESULT = "ReportDirectiveHandlingResult"; + } + public static class DeviceSetup { public static final String SETUP_COMPLETED = "SetupCompleted"; public static final String SETUP_COMPLETED_RESPONSE = "SetupCompletedResponse"; @@ -181,6 +189,8 @@ public static class APL { public static final String SEND_USER_EVENT = "SendUserEvent"; public static final String SET_APL_MAX_VERSION = "SetAPLMaxVersion"; public static final String SET_DOCUMENT_IDLE_TIMEOUT = "SetDocumentIdleTimeout"; + public static final String SET_PLATFORM_PROPERTY = "SetPlatformProperty"; + public static final String UPDATE_APL_RUNTIME_PROPERTIES = "UpdateAPLRuntimeProperties"; } public static class AudioInput { @@ -189,9 +199,11 @@ public static class AudioInput { } public static class AudioOutput { + public static final String AUDIO_FOCUS_EVENT = "AudioFocusEvent"; public static final String GET_DURATION = "GetDuration"; public static final String GET_NUM_BYTES_BUFFERED = "GetNumBytesBuffered"; public static final String GET_POSITION = "GetPosition"; + public static final String MAY_DUCK = "MayDuck"; public static final String MEDIA_ERROR = "MediaError"; public static final String MEDIA_STATE_CHANGED = "MediaStateChanged"; public static final String MUTED_STATE_CHANGED = "MutedStateChanged"; @@ -200,7 +212,9 @@ public static class AudioOutput { public static final String PREPARE = "Prepare"; public static final String RESUME = "Resume"; public static final String SET_POSITION = "SetPosition"; + public static final String START_DUCKING = "StartDucking"; public static final String STOP = "Stop"; + public static final String STOP_DUCKING = "StopDucking"; public static final String VOLUME_CHANGED = "VolumeChanged"; } @@ -238,6 +252,15 @@ public static class Messaging { public static final String UPLOAD_CONVERSATIONS = "UploadConversations"; } + public static class MediaPlaybackRequestor { + public static final String REQUEST_MEDIA_PLAYBACK = "RequestMediaPlayback"; + public static final String MEDIA_PLAYBACK_RESPONSE = "MediaPlaybackResponse"; + public static final String SUCCESS = "SUCCESS"; + public static final String FAILED_CAN_RETRY = "FAILED_CAN_RETRY"; + public static final String FAILED_TIMEOUT = "FAILED_TIMEOUT"; + public static final String ERROR = "ERROR"; + } + public static class Navigation { public static final String ANNOUNCE_MANEUVER = "AnnounceManeuver"; public static final String ANNOUNCE_ROAD_REGULATION = "AnnounceRoadRegulation"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/ContactsConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/ContactsConstants.java similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/ContactsConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/ContactsConstants.java diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java similarity index 86% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java index c4d8d1462..f03b6f7cf 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/MediaConstants.java @@ -30,6 +30,12 @@ public static class MediaError { public static final String MEDIA_ERROR_INTERNAL_DEVICE_ERROR = "MEDIA_ERROR_INTERNAL_DEVICE_ERROR"; } + public static class AudioFocusEvent { + public static final String REPORT_DUCKING_STARTED = "REPORT_DUCKING_STARTED"; + public static final String REPORT_DUCKING_STOPPED = "REPORT_DUCKING_STOPPED"; + } + + public static final String FOCUS_ACTION = "focusAction"; public static final String TOKEN = "token"; public static final String CHANNEL = "channel"; public static final String STATE = "state"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NavigationConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NavigationConstants.java similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NavigationConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NavigationConstants.java diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NetworkConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NetworkConstants.java similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NetworkConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/NetworkConstants.java diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java similarity index 76% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java index 5900282b3..a05e23966 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/PlaybackConstants.java @@ -32,6 +32,13 @@ public static class ToggleButton { public static final String THUMBS_DOWN = "THUMBS_DOWN"; } + public static class RequestMediaPlayback { + public static final String INVOCATION_REASON = "invocationReason"; + public static final String ELAPSED_BOOT_TIME = "elapsedBootTime"; + public static final String REASON_AUTOMOTIVE_STARTUP = "AUTOMOTIVE_STARTUP"; + public static final String EXPLICIT_USER_ACTION = "EXPLICIT_USER_ACTION"; + } + public static final String BUTTON = "button"; public static final String TOGGLE = "toggle"; public static final String ACTION = "action"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java similarity index 91% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java index 44d8894d3..567ae1f9f 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TelephonyConstants.java @@ -6,6 +6,7 @@ public class TelephonyConstants { public static final String ACTION_UPDATE_DEVICE_COFIGURATION = "com.amazon.aacstelephony.updateDeviceConfiguration"; public static final String ACTION_BLUETOOTH_STATE_CONNECTED = "com.amazon.aacstelephony.bluetooth.connected"; public static final String ACTION_BLUETOOTH_STATE_DISCONNECTED = "com.amazon.aacstelephony.bluetooth.disconnected"; + public static final String ACTION_BLUETOOTH_STATE_CONNECTION_CHECK_COMPLETED = "com.amazon.aacstelephony.bluetooth.connectionCheckCompleted"; public static final String CATEGORY_AACS_TELEPHONY = "com.amazon.aacstelephony"; public static final String STATE = "state"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TemplateRuntimeConstants.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TemplateRuntimeConstants.java similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TemplateRuntimeConstants.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/TemplateRuntimeConstants.java diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java similarity index 94% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java rename to aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java index 86e6b1547..2d518a7d2 100644 --- a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java +++ b/aacs/android/common/constants/aacsconstants/src/main/java/com/amazon/aacsconstants/Topic.java @@ -40,8 +40,10 @@ public class Topic { public static final String AUDIO_OUTPUT = "AudioOutput"; public static final String CAR_CONTROL = "CarControl"; public static final String CBL = "CBL"; + public static final String CUSTOM_DOMAIN = "CustomDomain"; public static final String ALEXA_CONNECTIVITY = "AlexaConnectivity"; public static final String LOCATION_PROVIDER = "LocationProvider"; + public static final String MEDIA_PLAYBACK_REQUESTER = "MediaPlaybackRequestor"; public static final String MESSAGING = "Messaging"; public static final String NAVIGATION = "Navigation"; public static final String NETWORK_INFO_PROVIDER = "NetworkInfoProvider"; diff --git a/platforms/android/alexa-auto-client-service/constants/aacsconstants/src/test/java/com/amazon/aacsconstants/ExampleUnitTest.java b/aacs/android/common/constants/aacsconstants/src/test/java/com/amazon/aacsconstants/ExampleUnitTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/aacsconstants/src/test/java/com/amazon/aacsconstants/ExampleUnitTest.java rename to aacs/android/common/constants/aacsconstants/src/test/java/com/amazon/aacsconstants/ExampleUnitTest.java diff --git a/aacs/android/common/constants/build.gradle b/aacs/android/common/constants/build.gradle new file mode 100644 index 000000000..4fafc3c38 --- /dev/null +++ b/aacs/android/common/constants/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + + repositories { + google() + mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/platforms/android/app-components/alexa-auto-telephony/gradle.properties b/aacs/android/common/constants/gradle.properties similarity index 100% rename from platforms/android/app-components/alexa-auto-telephony/gradle.properties rename to aacs/android/common/constants/gradle.properties diff --git a/platforms/android/alexa-auto-client-service/constants/settings.gradle b/aacs/android/common/constants/settings.gradle similarity index 100% rename from platforms/android/alexa-auto-client-service/constants/settings.gradle rename to aacs/android/common/constants/settings.gradle diff --git a/extensions/bluetooth/aacs/android/.gitignore b/aacs/android/common/ipc/.gitignore similarity index 100% rename from extensions/bluetooth/aacs/android/.gitignore rename to aacs/android/common/ipc/.gitignore diff --git a/aacs/android/common/ipc/README.md b/aacs/android/common/ipc/README.md new file mode 100644 index 000000000..f0e7bd37f --- /dev/null +++ b/aacs/android/common/ipc/README.md @@ -0,0 +1,213 @@ +# Using the IPC Library with AACS + +## Overview +The IPC (inter-process communication) library implements the IPC protocol required for communications between an HMI (human-machine interface) application +and AACS (Alexa Auto Client Service). The library enables AACS to send and receive arbitrary types of payloads of +arbitrary sizes. The library is implemented using standard Android constructs. You can use it as-is or +as a reference when implementing IPC for your app. + +## Getting Started with the IPC Library +**NOTE**: This section assumes that you have completed the steps for building and installing AACS. + +To build the IPC library, follow these steps: +1) Enter the following commands: + ~~~ + cd $AACS_HOME/common/ipc + gradle assembleDebug + ~~~ + The `aacsipc-debug.aar` file is built. + +1) Copy `aacsipc-debug.aar` to the `libs` folder of your app. + +## API Usage Guide + +The IPC library consists of two main classes for apps to interface with: [AACSSender](#AACSSender) +and [AACSReceiver](#AACSReceiver). For an additional in-code example that illustrates how an app uses the IPC library, see an AACS Android-service project. + +### AACSSender + +`AACSSender` enables an application to send data to another application that +uses [AACSReceiver](#AACSReceiver). + +**Initialization** - When `AACSSender` initializes, it instantiates an `AACSSender` object as follows: + +```java + // AACSSender posts callbacks to the looper specified in the constructor + // argument. If none is provided, it uses the mainlooper. + AACSSender mAACSSender = new AACSSender(Looper.getMainLooper()); +``` + +**Sending a message** - `AACSSender` sends non-streaming data, such as an AASB (Alexa Auto Service Bridge) JSON message, to AACS as follows: + +```java + // replace with the entire aasb json message + String aasbMessage = "..."; + + // replace with topic of the aasb message + String aasbTopic = "..."; + + // replace with action of the aasb message + String aasbAction = "..."; + + // can also be a list of multiple targets List + TargetComponent target = TargetComponent.withComponent(new ComponentName( + "com.amazon.alexaautoclientservice", "com.amazon.alexaautoclientservice.AlexaAutoClientService"), + TargetComponent.Type.SERVICE); + + Context context = getApplicationContext(); + + mAACSSender.sendAASBMessageAnySize(aasbMessage, aasbAction, aasbTopic, target(s), context); +``` + +**Fetching data from AACS** - To stream data to the application, such as audio data, +AACS first sends the application a `streamId` (for example, the AASB message `AudioOutput/Prepare`). The application +then requests the stream associated with that `streamId` from AACS through a `fetch` function as follows: + +```java + // streamId previously extracted from the aasb message AudioOutput/Prepare> + String streamId = "..."; + + Context context = getApplicationContext(); + + TargetComponent target = TargetComponent.withComponent(new ComponentName( + "com.amazon.alexaautoclientservice", "com.amazon.alexaautoclientservice.AlexaAutoClientService"), + TargetComponent.Type.SERVICE); + + AACSSender.StreamFetchedFromReceiverCallback fetchCallback = (readPipe) -> { + // readPipe is a ParcelFileDescriptor + // inputStream is a ParcelFileDescriptor.AutoCloseInputStream that can be created from the given ParcelFileDescriptor + ParcelFileDescriptor.AutoCloseInputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(readPipe); + + // this callback gets triggered on the looper provided during construction. + // If this callback is triggered on the mainlooper, it is advised + // to delegate the work to a different thread to avoid + // triggering an ANR (application not responding) error. + + // perform application logic as necessary, reading the stream + // (you could read the stream here, or queue it onto a different thread, etc) + + // once finished with the stream, you must close it. + // (if you queue it onto a different thread, close it there) + inputStream.close(); +}; + +mAACSSender.fetch(streamId, fetchCallback, target, context); +``` + + +**AACS fetching data from OEM application** - If the default audio input platform handler is enabled and an external audio stream source is used, when AACS receives a `StartAudioInput` or `StopAudioInput` message, it sends an IPC fetch request or an IPC cancel fetch request. This request fetches or cancels fetching the audio input stream from the application. The application must implement `AACSReceiver.FetchStreamCallback`, provide the write pipe associated with the audio stream in `onStreamRequested(String streamId, ParcelFileDescriptor writePipe)` method, and stop providing the stream in `onStreamFetchCancelled(String streamId)` method, as shown in the following example: + +~~~java + AACSReceiver.FetchStreamCallback aasbFetchCallback = new AACSReceiver.FetchStreamCallback() { + @Override + public void onStreamRequested(String streamId, ParcelFileDescriptor writePipe) { + // Save the streamId and create a stream using the writePipe + ParcelFileDescriptor.AutoCloseOutputStream stream = new ParcelFileDescriptor.AutoCloseOutputStream(writePipe); + + // Start writing your streamed data to the ParcelFileDescriptor.AutoCloseOutputStream + + // Close stream and pipe as needed when streaming is done + } + + @Override + public void onStreamFetchCancelled(String streamId) { + // Stop writing to the ParcelFileDescriptor.AutoCloseOutputStream + // associated with the given streamId + } + } +~~~ + +**Pushing data to AACS** - To receive streamed data from the application, such as +microphone data, AACS first sends the application a `streamId` (for example, the AASB message `AudioInput/StartAudioInput`). +The application then sends a stream associated with AACS together with `streamId` to indicate which request +it's fulfilling through the `push` function as shown in the following code: + +```java + // streamId previously extracted from the aasb message AudioInput/StartAudioInput> + String streamId = "..."; + + Context context = getApplicationContext(); + + TargetComponent target = TargetComponent.withComponent(new ComponentName( + "com.amazon.alexaautoclientservice", "com.amazon.alexaautoclientservice.AlexaAutoClientService"), + TargetComponent.Type.SERVICE); + + AACSSender.PushToStreamIdCallback pushCallback = (streamId, writePipe) -> { + // writePipe is a ParcelFileDescriptor + // outputStream is a ParcelFileDescriptor.AutoCloseOutputStream that can be created from the given ParcelFileDescriptor + ParcelFileDescriptor.AutoCloseOutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(writePipe); + + // this callback gets triggered on the looper provided during construction. + // If this callback is triggered on the mainlooper, it is advised + // to delegate the work to a different thread to avoid + // triggering an ANR error. + + // copy microphone data to outputStream + + //once finished with the stream, you must close it. + // (if you queue it onto a different thread, close it there) + outputStream.close(); + }; + + mAACSSender.push(streamId, pushCallback, target, context); +``` +**Sending configuration data to AACS** - The application can send configuration data to AACS as follows: + +```java + String configMessage = "{\n" + + " \"configFilepaths\" : [\"" + path + "\"]," + + " \"configStrings\" : []" + + "}"; + + TargetComponent target = TargetComponent.withComponent(new ComponentName( + "com.amazon.alexaautoclientservice", "com.amazon.alexaautoclientservice.AlexaAutoClientService"), + TargetComponent.Type.SERVICE); + + mAACSSender.sendConfigMessageAnySize(configMessage, target, getApplicationContext()); +``` + +`configMessage` must include the paths to the configuration file or the config strings. + + +### AACSReceiver + +`AACSReceiver` enables an application to receive data from another application that +uses [AACSSender](#AACSSender). + +**Initialization** - Most of the logic for `AACSReceiver` is specified in callbacks. `AACSReceiver` is initialized +by a builder. Callbacks must be provided to the builder before the builder creates `AACSReceiver`. The following code shows how a builder creates `AACSReceiver`: + +```java + AACSReceiver.Builder builder = new AACSReceiver.Builder(); + AACSReceiver receiver = builder + + // this step is optional. If no looper is provided, + // the main looper is used by default. + // .receive() and .shutdown() must be called from the indicated + // looper. All callbacks that AACSReceiver calls or invokes are also posted + // to that looper. + .withLooper(Looper.Looper.getMainLooper) + + // this callback is invoked when the receiver gets a non-streamed message, + // such as an AASB message. + .withAASBCallback((message) -> { + // Perform application logic based + // on the AASB message in messageString. + }).build(); +``` + + +**Receiving from the sender** - `AACSReceiver` doesn't create any direct intent receiver, which can be a service, activity, or broadcast receiver. The `AACSReceiver` relies +on the service, activity, or broadcast receiver in the app to forward intents to it. The following code is an example illustrating how an activity overrides `onNewIntent` and sends an intent to be received by `AACSReceiver`: + +```java + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + + setIntent(intent); + + // Intents that are sent by AACS should be received here. + mAACSReceiver.receiveMessage(intent); + } +``` diff --git a/platforms/android/app-components/alexa-auto-apps-common-util/.gitignore b/aacs/android/common/ipc/aacsipc/.gitignore similarity index 100% rename from platforms/android/app-components/alexa-auto-apps-common-util/.gitignore rename to aacs/android/common/ipc/aacsipc/.gitignore diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/build.gradle b/aacs/android/common/ipc/aacsipc/build.gradle similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/build.gradle rename to aacs/android/common/ipc/aacsipc/build.gradle diff --git a/platforms/android/modules/apl-render/proguard-rules.pro b/aacs/android/common/ipc/aacsipc/proguard-rules.pro similarity index 100% rename from platforms/android/modules/apl-render/proguard-rules.pro rename to aacs/android/common/ipc/aacsipc/proguard-rules.pro diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/androidTest/java/com/amazon/aacsipc/ExampleInstrumentedTest.java b/aacs/android/common/ipc/aacsipc/src/androidTest/java/com/amazon/aacsipc/ExampleInstrumentedTest.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/androidTest/java/com/amazon/aacsipc/ExampleInstrumentedTest.java rename to aacs/android/common/ipc/aacsipc/src/androidTest/java/com/amazon/aacsipc/ExampleInstrumentedTest.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/AndroidManifest.xml b/aacs/android/common/ipc/aacsipc/src/main/AndroidManifest.xml similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/AndroidManifest.xml rename to aacs/android/common/ipc/aacsipc/src/main/AndroidManifest.xml diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSPinger.java b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSPinger.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSPinger.java rename to aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSPinger.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSReceiver.java b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSReceiver.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSReceiver.java rename to aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSReceiver.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java similarity index 97% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java rename to aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java index 82346eee0..9b04feeba 100644 --- a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java +++ b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/AACSSender.java @@ -212,6 +212,17 @@ public Future sendConfigMessageAnySize(String message, TargetComponent return sendMessage(message, intentAction, intentCategory, target, context); } + public Future sendMessageAnySize(String message, String intentAction, String intentCategory, + List targets, Context context) { + checkLogStringValid(message, "message", "sendMessageAnySize"); + checkLogStringValid(intentCategory, "category", "sendMessageAnySize"); + checkLogStringValid(intentAction, "action", "sendMessageAnySize"); + checkLogArgNonNull(targets, "targets", "sendMessageAnySize"); + checkLogArgNonNull(context, "context", "sendMessageAnySize"); + + return sendMessage(message, intentAction, intentCategory, targets, context); + } + private Future sendMessage( String message, String action, String category, List targets, Context context) { if (willMessageFitAsEmbedded(message)) { diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/IPCConstants.java b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/IPCConstants.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/IPCConstants.java rename to aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/IPCConstants.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/SenderMap.java b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/SenderMap.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/SenderMap.java rename to aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/SenderMap.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/TargetComponent.java b/aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/TargetComponent.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/main/java/com/amazon/aacsipc/TargetComponent.java rename to aacs/android/common/ipc/aacsipc/src/main/java/com/amazon/aacsipc/TargetComponent.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/DummyService.java b/aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/DummyService.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/DummyService.java rename to aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/DummyService.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSReceiver.java b/aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSReceiver.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSReceiver.java rename to aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSReceiver.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSSender.java b/aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSSender.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSSender.java rename to aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestAACSSender.java diff --git a/platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestUtils.java b/aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestUtils.java similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestUtils.java rename to aacs/android/common/ipc/aacsipc/src/test/java/com/amazon/aacsipc/TestUtils.java diff --git a/aacs/android/common/ipc/build.gradle b/aacs/android/common/ipc/build.gradle new file mode 100644 index 000000000..2aba04ea9 --- /dev/null +++ b/aacs/android/common/ipc/build.gradle @@ -0,0 +1,26 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + google() + mavenCentral() + + } + dependencies { + classpath 'com.android.tools.build:gradle:3.6.2' + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +} + +allprojects { + repositories { + google() + mavenCentral() + + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/platforms/android/alexa-auto-client-service/ipc/gradle.properties b/aacs/android/common/ipc/gradle.properties similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/gradle.properties rename to aacs/android/common/ipc/gradle.properties diff --git a/platforms/android/alexa-auto-client-service/ipc/settings.gradle b/aacs/android/common/ipc/settings.gradle similarity index 100% rename from platforms/android/alexa-auto-client-service/ipc/settings.gradle rename to aacs/android/common/ipc/settings.gradle diff --git a/aacs/android/conanfile.py b/aacs/android/conanfile.py new file mode 100644 index 000000000..d81551e4c --- /dev/null +++ b/aacs/android/conanfile.py @@ -0,0 +1,44 @@ +import uuid, os +from conans import ConanFile, tools, CMake + +class AlexaAutoClientService(ConanFile): + settings = "os", "compiler", "build_type", "arch" + version = "dev" + exports = "*", "!*.txt" + name = "alexaautoclientservice" + options = { + "aac_version": "ANY", + "aac_modules": "ANY", + "extra_modules": "ANY", + "with_sensitive_logs" : [True, False] + } + + default_options = { + "aac_version": "dev", + "aac_modules": "core,aasb,alexa,bluetooth,apl,cbl,address-book,car-control,custom-domain,connectivity,messaging,navigation,phone-control,text-to-speech,text-to-speech-provider", + "extra_modules": None, + "with_sensitive_logs" : False + } + + def requirements(self): + module_list = set( str(self.options.aac_modules).split(",") ) + if self.options.extra_modules: + module_list.update( str(self.options.extra_modules).split(",") ) + for next in module_list: + module = next.strip().casefold() + req = f"aac-module-{module}" + self.options[req].with_aasb = True + self.options[req].with_messages = True + if (self.options.with_sensitive_logs == True and self.settings.build_type == "Debug"): + self.options[req].with_sensitive_logs = True + self.requires(f"{req}/{self.options.aac_version}") + + def imports(self): + libs_folder = os.path.abspath( os.path.join( __file__, "..", "service", "core-service", "libs")) + self.copy("*.aar",dst=libs_folder,keep_path=False) + + def package(self): + self.copy("*.aar") + + def deploy(self): + self.copy("*.aar", keep_path=False) diff --git a/aacs/android/restrictedAssets/LICENSE_PMLA b/aacs/android/restrictedAssets/LICENSE_PMLA new file mode 100644 index 000000000..2d40bc239 --- /dev/null +++ b/aacs/android/restrictedAssets/LICENSE_PMLA @@ -0,0 +1,9 @@ +Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +The Alexa Auto Assets provided here (the “Materials") are licensed as "Program Materials" under the Program Materials License Agreement (the "Agreement") in connection with the Alexa Voice Service Program. The Agreement is available at https://developer.amazon.com/public/support/pml.html. See the Agreement for the specific terms and conditions of the Agreement. Capitalized terms not defined in this file have the meanings given to them in the Agreement. + +In addition to the terms and conditions of the Agreement, the following terms and conditions apply to these Materials. In the event of a conflict between the terms and conditions of the Agreement and those of this file, the terms and conditions of this file will apply. + +1. These Materials may only be used in connection with the Alexa Voice Service Program. + +2. These Materials and all related documentation are Restricted Program Materials as defined in the Agreement. diff --git a/aacs/android/restrictedAssets/NOTICE b/aacs/android/restrictedAssets/NOTICE new file mode 100644 index 000000000..079b0a5c1 --- /dev/null +++ b/aacs/android/restrictedAssets/NOTICE @@ -0,0 +1 @@ +Alexa Trademarked Logo and Graphics. Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. diff --git a/aacs/android/restrictedAssets/drawable/alexa_bubble_small.png b/aacs/android/restrictedAssets/drawable/alexa_bubble_small.png new file mode 100644 index 0000000000000000000000000000000000000000..882585411e7f9f7a43b95149f6469038ae670513 GIT binary patch literal 983 zcmV;|11S87P)F)vH?t>evn9T%$rUUw$uKfhbJG*z5H{>NxFkOtu+ym0m}YOfv+?7KLa&T0Z02c zIPM~l&U@F!Q&$U=y(+2mZ~zLR@zSKV_PzF6>qf7K#@ZD7>=S8a z|MRgTJBL?HW*uDx?*+yZOo}~mIl@@mPu7>jMbI_UDW;%&aS>VpFPOqvFS*%;bcRVK z--;XyE#{G{=5Ab?-Wk_T7>sX6jIWbeLOSF633pgTd@j9HOuF0x;XYan@p|aTsYoZ7 zqIGM8!T4Mw8KIP}8#jw&I}itrP&Q#{4Uu0;jhLDgF8!s?vcEh&3%9nk)n z-7(`KjMiG~-H84r*DjzRv!wR{40-L1WBc>*nNBbjPg=YdZx9@j;kRtIn3br3^XmQJ zsaO%`;9ptYtx$eLub_R5bdBr~5tDEq8S;p~VxoN#=^Xi~NfDngyhmJuEr#P6X$c-# zhj53=+LR!N)AVj|Pn)-txd3Y1GqVMfF47sY=VULC2?dGm4Ul!Dl|Vt)sJj#n)(2Op zexzMd3S>f~6v(_qI$g8CI*~+mvlqH91pJr&b~-VH$u4>Xj}#E zaqJm?21p}))41olQgszbBb|hFVr_heC9A=43*ANfSzt^FWI`js{mk&(k*);>bAe1~ zD1l7fk*);7xj-f~lt8BHNFN2lTg*`WlE?)z$6Ib9D9lja1t(1ekeyhzT&|I@6Udan zNwYuqXr^a6TyuZPl?wgL^+2<~=DJ(J9ZKMvqs(9n8077r#cu%wfWn*UB* zgC$5X*(B+Lri_er8q8c;iVdcs?mcu&VUO(bE9f7rMhe9>jB1BQw^BbA&8L;nz?jiO z`&IbN!@l~cZ^}^NVQ378342q78=<{oNavKXL~C6MjZMKN<$VZO+Hg42JJm#JFqK$3 z6COjl@V*`Lv23@BG($hmbxvyhhT&2az%S&46%)thCGDb$^@wNIp7d3&MLWZ#J+g|p z#8b?U={NHC$%4NSi&d5pcDj*b$o>Jod+2%LJxk`{P)Yk$-Df#FXssV~xRs&MBUO6r z`u{nDBaWE#d}Q6~-ddX}!h_8}`H9m1kI^C^;|f1J{0q@NQ8kOT1keBg002ovPDHLk FV1mC8&dUG* literal 0 HcmV?d00001 diff --git a/aacs/android/restrictedAssets/drawable/alexa_logo.png b/aacs/android/restrictedAssets/drawable/alexa_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7173af3458c480715cf32a4faf9a1f6cb3f34073 GIT binary patch literal 5141 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:** Amazon recommends that you familiarize yourself with AACS by reading the [AACS README](../README.md). + + +## Table of Contents +- [AACS Sample App Architecture](#aacs-sample-app-architecture) +- [Prerequisites](#prerequisites) + - [Requirements for Using AACS Sample App](#requirements-for-using-aacs-sample-app) + - [Requirements for Using AACS Sample App with Preview Mode](#requirements-for-using-aacs-sample-app-with-preview-mode) + - [Requirements for Using AACS Sample App with APL](#requirements-for-using-aacs-sample-app-with-apl) + - [Requirements for Building AACS Sample App](#requirements-for-building-aacs-sample-app) + - [Requirements for Using Optional Features](#requirements-for-using-optional-features) +- [About App Components](#about-app-components) +- [Building the AACS Sample App using AACS AAR](#building-the-aacs-sample-app-using-aacs-aar) + - [Cloning the Auto SDK Repository](#cloning-the-auto-sdk-repository) + - [Editing the Configuration File](#editing-the-configuration-file) + - [Including Build Dependency (AAR)](#including-build-dependency-aar) + - [Building and Signing the AACS Sample App APK](#building-and-signing-the-aacs-sample-app-apk) +- [Alexa Setup](#alexa-setup) + - [Language Selection](#language-selection) + - [Starting Alexa on the Introduction Screen](#starting-alexa-on-the-introduction-screen) + - [Starting Authorization](#starting-authorization) + - [Alexa Configuration for Logged-in Users](#alexa-configuration-for-logged-in-users) +- [Using the Alexa Menu](#using-the-alexa-menu) + - [Alexa Menu for Preview Mode Users](#alexa-menu-for-preview-mode-users) + - [Alexa Menu for Signed-in Users](#alexa-menu-for-signed-in-users) + - [Alexa Menu Options](#alexa-menu-options) +- [Using the AACS Sample App](#using-the-aacs-sample-app) + - [Selecting Alexa as the Assistant](#selecting-alexa-as-the-assistant) + - [Using Alexa Custom Assistant Module Library for Animation](#using-alexa-custom-assistant-module-library-for-animation) + - [Using the AACS Sample App for Media Player](#using-the-aacs-sample-app-for-media-player) +- [Media Resume Last Playing Media After Platform Reboot](#media-resume-last-playing-media-after-platform-reboot) +- [Known Issues](#known-issues) + +## AACS Sample App Architecture +The following diagram illustrates the AACS Sample App Architecture. + +