├── settings.gradle
├── app
├── src
│ └── main
│ │ ├── res
│ │ ├── raw
│ │ │ ├── error.ogg
│ │ │ ├── sonar.ogg
│ │ │ ├── success.ogg
│ │ │ ├── processing.ogg
│ │ │ ├── menu.top
│ │ │ └── localization_menu.top
│ │ ├── drawable
│ │ │ ├── hiding.png
│ │ │ ├── pepper_explanation.png
│ │ │ ├── button_shape_disabled.xml
│ │ │ ├── button_shape_pressed.xml
│ │ │ ├── button_shape_selected.xml
│ │ │ ├── button_shape_unselected.xml
│ │ │ ├── ic_baseline_back.xml
│ │ │ ├── ic_baseline_close.xml
│ │ │ ├── ic_check.xml
│ │ │ ├── button_background_selector.xml
│ │ │ └── ic_warning.xml
│ │ ├── font
│ │ │ ├── open_sans_bold.ttf
│ │ │ └── open_sans_semibold.ttf
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── color
│ │ │ ├── navigation_tint_selector.xml
│ │ │ └── button_text_color_selector.xml
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── colors.xml
│ │ │ ├── styles.xml
│ │ │ └── strings.xml
│ │ ├── animator
│ │ │ └── button_state_list_animator.xml
│ │ └── layout
│ │ │ ├── activity_introduction.xml
│ │ │ ├── fragment_localization_menu.xml
│ │ │ ├── activity_menu.xml
│ │ │ ├── activity_localization.xml
│ │ │ ├── fragment_go_to_origin.xml
│ │ │ ├── fragment_localize.xml
│ │ │ └── activity_mapping.xml
│ │ ├── assets
│ │ ├── robot
│ │ │ └── robotsdk.xml
│ │ └── lottie
│ │ │ └── splashy_loader.json
│ │ ├── java
│ │ └── com
│ │ │ └── softbankrobotics
│ │ │ └── sample
│ │ │ └── returntomapframe
│ │ │ ├── localization
│ │ │ ├── ScreenState.java
│ │ │ ├── gotoorigin
│ │ │ │ ├── GoToOriginState.java
│ │ │ │ ├── GoToOriginEvent.java
│ │ │ │ ├── GoToOriginScreen.java
│ │ │ │ ├── GoToOriginMachine.java
│ │ │ │ ├── GoToOriginRobot.java
│ │ │ │ └── GoToOriginFragment.java
│ │ │ ├── ScreenEvent.java
│ │ │ ├── localize
│ │ │ │ ├── LocalizeState.java
│ │ │ │ ├── LocalizeEvent.java
│ │ │ │ ├── LocalizeScreen.java
│ │ │ │ ├── LocalizeMachine.java
│ │ │ │ ├── LocalizeRobot.java
│ │ │ │ └── LocalizeFragment.java
│ │ │ ├── Robot.java
│ │ │ ├── Screen.java
│ │ │ ├── ScreenMachine.java
│ │ │ ├── localizationmenu
│ │ │ │ ├── LocalizationMenuScreen.java
│ │ │ │ ├── LocalizationMenuFragment.java
│ │ │ │ └── LocalizationMenuRobot.java
│ │ │ ├── LocalizeManager.java
│ │ │ └── LocalizationActivity.java
│ │ │ ├── mapping
│ │ │ ├── MappingState.java
│ │ │ ├── MappingEvent.java
│ │ │ ├── MappingMachine.java
│ │ │ ├── MappingActivity.java
│ │ │ └── MappingRobot.java
│ │ │ ├── App.java
│ │ │ ├── utils
│ │ │ └── FutureCancellations.java
│ │ │ ├── introduction
│ │ │ └── IntroductionActivity.java
│ │ │ ├── core
│ │ │ └── MapManager.kt
│ │ │ └── menu
│ │ │ └── MenuActivity.java
│ │ └── AndroidManifest.xml
├── proguard-rules.pro
└── build.gradle
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── README.md
├── COPYING.md
├── gradlew.bat
├── .gitignore
└── gradlew
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/error.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/raw/error.ogg
--------------------------------------------------------------------------------
/app/src/main/res/raw/sonar.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/raw/sonar.ogg
--------------------------------------------------------------------------------
/app/src/main/res/raw/success.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/raw/success.ogg
--------------------------------------------------------------------------------
/app/src/main/res/raw/processing.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/raw/processing.ogg
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hiding.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/drawable/hiding.png
--------------------------------------------------------------------------------
/app/src/main/assets/robot/robotsdk.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/font/open_sans_bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/font/open_sans_bold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/font/open_sans_semibold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/font/open_sans_semibold.ttf
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/pepper_explanation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aldebaran/qisdk-sample-return-to-map-frame/HEAD/app/src/main/res/drawable/pepper_explanation.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_shape_disabled.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_shape_pressed.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_shape_selected.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Oct 03 15:22:29 CEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/navigation_tint_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_shape_unselected.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_back.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_close.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 32sp
4 | 24sp
5 | 2dp
6 | 7dp
7 | 10dp
8 | 20dp
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/ScreenState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | /**
8 | * A state for screens. Indicates the current screen.
9 | */
10 | public enum ScreenState {
11 | NONE,
12 | LOCALIZATION_MENU,
13 | LOCALIZE,
14 | GO_TO_ORIGIN,
15 | END,
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/gotoorigin/GoToOriginState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.gotoorigin;
6 |
7 | /**
8 | * A state for {@link GoToOriginScreen}.
9 | */
10 | enum GoToOriginState {
11 | IDLE,
12 | BRIEFING,
13 | MOVING,
14 | ERROR,
15 | SUCCESS,
16 | END,
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/mapping/MappingState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.mapping;
6 |
7 | /**
8 | * A state for {@link MappingActivity}.
9 | */
10 | enum MappingState {
11 | IDLE,
12 | BRIEFING,
13 | ADVICES,
14 | MAPPING,
15 | SAVING_MAP,
16 | ERROR,
17 | SUCCESS,
18 | END,
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_check.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/ScreenEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | /**
8 | * An event for screens.
9 | */
10 | public enum ScreenEvent {
11 | FOCUS_GAINED,
12 | FOCUS_LOST,
13 | BACK,
14 | LOCALIZE_SELECTED,
15 | GO_TO_ORIGIN_SELECTED,
16 | LOCALIZE_END,
17 | GO_TO_ORIGIN_END,
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localize/LocalizeState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localize;
6 |
7 | /**
8 | * A state for {@link LocalizeScreen}.
9 | */
10 | enum LocalizeState {
11 | IDLE,
12 | BRIEFING,
13 | ADVICES,
14 | LOADING_MAP,
15 | LOCALIZING,
16 | ERROR,
17 | SUCCESS,
18 | END,
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/menu.top:
--------------------------------------------------------------------------------
1 | topic: ~menu()
2 |
3 | concept: (create) ["{"create a"} new map" "create"]
4 | concept: (use) ["{use} saved map" "use"]
5 | concept: (ok) ^rand["got it" alright]
6 |
7 | proposal: %start $proposal %start_timer
8 | u1: (~create) %create %stop_timer ~ok %create_end
9 | u1: (~use) %use %stop_timer ^first["%map ~ok %use_end" "You need to create a map first ^sameProposal"]
10 | u1: (repeat) %stop_timer ^sameProposal
11 | u1: (e:Dialog/NotUnderstood) %stop_timer Sorry? ^sameProposal
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/gotoorigin/GoToOriginEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.gotoorigin;
6 |
7 | /**
8 | * An event for {@link GoToOriginScreen}.
9 | */
10 | enum GoToOriginEvent {
11 | START,
12 | STOP,
13 | START_GO_TO_ORIGIN,
14 | GO_TO_ORIGIN_SUCCEEDED,
15 | GO_TO_ORIGIN_FAILED,
16 | SUCCESS_CONFIRMED,
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/mapping/MappingEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.mapping;
6 |
7 | /**
8 | * An event for {@link MappingActivity}.
9 | */
10 | enum MappingEvent {
11 | FOCUS_GAINED,
12 | FOCUS_LOST,
13 | START_MAPPING,
14 | ADVICES_ENDED,
15 | MAPPING_SUCCEEDED,
16 | MAPPING_FAILED,
17 | SAVING_MAP_SUCCEEDED,
18 | SAVING_MAP_FAILED,
19 | SUCCESS_CONFIRMED,
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 | #9e9e9e
8 |
9 | #e0e0e0
10 | #f5f5f5
11 | #eeeeee
12 | #4caf50
13 |
14 | #888888
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localize/LocalizeEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localize;
6 |
7 | /**
8 | * An event for {@link LocalizeScreen}.
9 | */
10 | enum LocalizeEvent {
11 | START,
12 | STOP,
13 | START_LOCALIZE,
14 | ADVICES_ENDED,
15 | LOADING_MAP_SUCCEEDED,
16 | LOADING_MAP_FAILED,
17 | LOCALIZE_SUCCEEDED,
18 | LOCALIZE_FAILED,
19 | SUCCESS_CONFIRMED,
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/localization_menu.top:
--------------------------------------------------------------------------------
1 | topic: ~localization_menu()
2 |
3 | concept: (localize) ["localize {yourself}"]
4 | concept: (go_to_origin) ["go to {"{your} [initial origin] position"}"]
5 | concept: (ok) ^rand["got it" alright]
6 |
7 | proposal: %start $proposal %start_timer
8 | u1: (~localize) %localize %stop_timer ~ok %localize_end
9 | u1: (~go_to_origin) %go_to_origin %stop_timer ^first["%localized ~ok %go_to_origin_end" "I need to localize myself first ^sameProposal"]
10 | u1: (repeat) %stop_timer ^sameProposal
11 | u1: (e:Dialog/NotUnderstood) %stop_timer Sorry? ^sameProposal
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe;
6 |
7 | import android.app.Application;
8 |
9 | import com.crashlytics.android.Crashlytics;
10 |
11 | import io.fabric.sdk.android.Fabric;
12 |
13 | public class App extends Application {
14 | @Override
15 | public void onCreate() {
16 | super.onCreate();
17 | if (!BuildConfig.DEBUG) {
18 | Fabric.with(this, new Crashlytics());
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/res/color/button_text_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
10 |
15 |
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/Robot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | import com.aldebaran.qi.Future;
8 |
9 | import androidx.annotation.NonNull;
10 |
11 | /**
12 | * A robotic component.
13 | */
14 | public interface Robot {
15 | /**
16 | * Meant to be called when the robotic component must stop.
17 | * This is the place where related actions must be stopped.
18 | *
19 | * @return A {@link Future} that is a success when the robotic component has correctly stopped.
20 | */
21 | @NonNull
22 | Future stop();
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_background_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
10 |
15 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_warning.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | android.enableJetifier=true
10 | android.useAndroidX=true
11 | org.gradle.jvmargs=-Xmx1536m
12 | # When configured, Gradle will run in incubating parallel mode.
13 | # This option should only be used with decoupled projects. More details, visit
14 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
15 | # org.gradle.parallel=true
16 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/Screen.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | import com.aldebaran.qi.Future;
8 | import com.aldebaran.qi.sdk.QiContext;
9 |
10 | import androidx.annotation.NonNull;
11 |
12 | /**
13 | * A screen. Coordinates a visual UI and a robotic UI.
14 | */
15 | public interface Screen {
16 | /**
17 | * Meant to be called when the screen must start.
18 | * This is the place where visual UI should be displayed and robotic UI should start its behavior.
19 | *
20 | * @param qiContext the qiContext
21 | */
22 | void start(@NonNull QiContext qiContext);
23 |
24 | /**
25 | * Meant to be called when the screen must stop.
26 | * This is the place where the visual UI and the robotic UI must be stopped.
27 | *
28 | * @return A {@link Future} that is a success when the screen has correctly stopped.
29 | */
30 | @NonNull
31 | Future stop();
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Return To MapFrame
2 |
3 | **Return To MapFrame** is an Android application for **Pepper the robot**. It was developed using the QiSDK (https://qisdk.softbankrobotics.com).
4 |
5 | This sample shows how to use **LocalizeAndMap** and **Localize** actions to:
6 | * Compute a map of an environment.
7 | * Use a map to make Pepper localize himself in the corresponding environment.
8 | * Make Pepper return to his original position, defined as the position where he started mapping his environment (map frame).
9 |
10 | ## Minimum configuration
11 |
12 | * Pepper 1.9.
13 | * API level 3.
14 | * A real robot (does not work on a virtual robot).
15 |
16 | ## Application flow
17 |
18 | ### Introduction
19 |
20 | Pepper will explain the purpose of this sample.
21 |
22 | ### Menu
23 |
24 | Select if you want to map Pepper's environment or use a saved map.
25 |
26 | ### Create a new map
27 |
28 | Follow instructions so that Pepper can map his surroundings and save the resulting map.
29 |
30 | ### Use saved map
31 |
32 | Select if you want Pepper to localize himself or if you want him to go to his initial position.
33 |
34 | ### Localization
35 |
36 | Follow instructions so that Pepper can localize himself in his environment.
37 |
38 | ### Go to initial position
39 |
40 | Follow instructions so that Pepper can go to his original position (map frame).
41 |
42 | ## License
43 |
44 | See the [COPYING](COPYING.md) file for the license.
45 |
--------------------------------------------------------------------------------
/app/src/main/res/animator/button_state_list_animator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
9 |
10 |
11 | -
14 |
19 |
20 |
21 | -
25 |
30 |
31 |
32 | -
33 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_introduction.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
31 |
32 |
--------------------------------------------------------------------------------
/COPYING.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2018, SoftBank Robotics Europe\
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are
6 | met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * Neither the name of the SoftBank Robotics Europe nor the names of
13 | its contributors may be used to endorse or promote products derived
14 | from this software without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
17 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SoftBank Robotics
20 | Europe BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/gotoorigin/GoToOriginScreen.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.gotoorigin;
6 |
7 | import com.aldebaran.qi.Future;
8 | import com.aldebaran.qi.sdk.QiContext;
9 | import com.softbankrobotics.sample.returntomapframe.R;
10 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizationActivity;
11 | import com.softbankrobotics.sample.returntomapframe.localization.Screen;
12 | import com.softbankrobotics.sample.returntomapframe.localization.ScreenEvent;
13 |
14 | import androidx.annotation.NonNull;
15 |
16 | /**
17 | * The go to origin screen.
18 | */
19 | public class GoToOriginScreen implements Screen {
20 |
21 | @NonNull
22 | private final LocalizationActivity activity;
23 | @NonNull
24 | private final GoToOriginRobot robot;
25 | @NonNull
26 | private final GoToOriginMachine machine = new GoToOriginMachine();
27 |
28 | public GoToOriginScreen(@NonNull LocalizationActivity activity) {
29 | this.activity = activity;
30 | this.robot = new GoToOriginRobot(machine);
31 | }
32 |
33 | @Override
34 | public void start(@NonNull QiContext qiContext) {
35 | activity.setNavigationTitle(R.string.go_to_origin_title);
36 |
37 | GoToOriginFragment fragment = GoToOriginFragment.newInstance(this, machine);
38 | activity.showFragment(fragment);
39 | robot.start(qiContext);
40 | }
41 |
42 | @NonNull
43 | @Override
44 | public Future stop() {
45 | return robot.stop();
46 | }
47 |
48 | void onGoToOriginEnd() {
49 | activity.getScreenMachine().post(ScreenEvent.GO_TO_ORIGIN_END);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localize/LocalizeScreen.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localize;
6 |
7 | import com.aldebaran.qi.Future;
8 | import com.aldebaran.qi.sdk.QiContext;
9 | import com.softbankrobotics.sample.returntomapframe.R;
10 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizationActivity;
11 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizeManager;
12 | import com.softbankrobotics.sample.returntomapframe.localization.Screen;
13 | import com.softbankrobotics.sample.returntomapframe.localization.ScreenEvent;
14 |
15 | import androidx.annotation.NonNull;
16 |
17 | /**
18 | * The localize screen.
19 | */
20 | public class LocalizeScreen implements Screen {
21 |
22 | @NonNull
23 | private final LocalizationActivity activity;
24 | @NonNull
25 | private final LocalizeRobot robot;
26 | @NonNull
27 | private final LocalizeMachine machine;
28 |
29 | public LocalizeScreen(@NonNull LocalizationActivity activity, @NonNull LocalizeManager localizeManager) {
30 | this.activity = activity;
31 | this.machine = new LocalizeMachine(localizeManager);
32 | this.robot = new LocalizeRobot(machine, localizeManager);
33 | }
34 |
35 | @Override
36 | public void start(@NonNull QiContext qiContext) {
37 | activity.setNavigationTitle(R.string.localize_title);
38 |
39 | LocalizeFragment fragment = LocalizeFragment.newInstance(this, machine);
40 | activity.showFragment(fragment);
41 | robot.start(qiContext);
42 | }
43 |
44 | @NonNull
45 | @Override
46 | public Future stop() {
47 | return robot.stop();
48 | }
49 |
50 | void onLocalizeEnd() {
51 | activity.getScreenMachine().post(ScreenEvent.LOCALIZE_END);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_localization_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
24 |
25 |
39 |
40 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories { maven { url 'https://maven.fabric.io/public' } }
3 | dependencies { classpath 'io.fabric.tools:gradle:1.29.0' }
4 | }
5 |
6 | apply plugin: 'com.android.application'
7 | apply plugin: 'kotlin-android'
8 | apply plugin: 'kotlin-android-extensions'
9 | apply plugin: 'io.fabric'
10 |
11 | repositories { maven { url 'https://maven.fabric.io/public' } }
12 |
13 | android {
14 | compileSdkVersion 29
15 | defaultConfig {
16 | applicationId 'com.softbankrobotics.sample.returntomapframe'
17 | minSdkVersion 23
18 | targetSdkVersion 29
19 | versionCode 7
20 | versionName '2.0.5'
21 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
22 | vectorDrawables.useSupportLibrary = true
23 | }
24 | buildTypes {
25 | release {
26 | minifyEnabled false
27 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
28 | }
29 | }
30 | compileOptions {
31 | sourceCompatibility JavaVersion.VERSION_1_8
32 | targetCompatibility JavaVersion.VERSION_1_8
33 | }
34 | }
35 |
36 | dependencies {
37 |
38 | // "libs" folder
39 | implementation fileTree(include: ['*.jar'], dir: 'libs')
40 |
41 | // Kotlin
42 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
43 |
44 | // AndroidX
45 | implementation 'androidx.appcompat:appcompat:1.1.0'
46 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
47 |
48 | // RxJava
49 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
50 | implementation 'io.reactivex.rxjava2:rxjava:2.2.19'
51 |
52 | // QiSDK
53 | implementation "com.aldebaran:qisdk:$qisdk_version"
54 | implementation "com.aldebaran:qisdk-design:$qisdk_version"
55 |
56 | // Fields & methods binding
57 | implementation "com.jakewharton:butterknife:$butterknife_version"
58 | annotationProcessor "com.jakewharton:butterknife-compiler:$butterknife_version"
59 |
60 | // After Effects animations
61 | implementation 'com.airbnb.android:lottie:2.7.0'
62 |
63 | // Crashlytics
64 | implementation('com.crashlytics.sdk.android:crashlytics:2.10.1@aar') { transitive = true }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/utils/FutureCancellations.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.utils;
6 |
7 | import com.aldebaran.qi.Future;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.annotation.Nullable;
14 |
15 | /**
16 | * Provide utility methods to cancel futures and to be notified when the cancellation is done.
17 | */
18 | public final class FutureCancellations {
19 |
20 | private FutureCancellations() {
21 | }
22 |
23 | /**
24 | * Cancel all the provided futures.
25 | *
26 | * @param futuresToCancel the futures to cancel
27 | * @return A {@link Future} that can only end in a success state, when all the provided futures are cancelled.
28 | * If the futures to cancel are already done, this method returns immediately.
29 | */
30 | @NonNull
31 | public static Future cancel(@Nullable Future>... futuresToCancel) {
32 | if (futuresToCancel == null) {
33 | return Future.of(null);
34 | }
35 |
36 | List> cancellations = new ArrayList<>();
37 |
38 | for (Future> futureToCancel : futuresToCancel) {
39 | Future cancellation = cancelFuture(futureToCancel);
40 | cancellations.add(cancellation);
41 | }
42 |
43 | Future>[] cancellationsArray = new Future>[cancellations.size()];
44 | return Future.waitAll(cancellations.toArray(cancellationsArray));
45 | }
46 |
47 | /**
48 | * Cancel the provided {@link Future}.
49 | *
50 | * @param futureToCancel the {@link Future} to cancel
51 | * @return A {@link Future} that can only end in a success state, when the provided {@link Future} is cancelled.
52 | * If the {@link Future} to cancel is already done, this method returns immediately.
53 | */
54 | @NonNull
55 | private static Future cancelFuture(@Nullable Future> futureToCancel) {
56 | if (futureToCancel == null) {
57 | return Future.of(null);
58 | }
59 |
60 | futureToCancel.requestCancellation();
61 | return futureToCancel.thenConsume(future -> {});
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
35 |
36 |
50 |
51 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_localization.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
20 |
30 |
31 |
44 |
45 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/introduction/IntroductionActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.introduction;
6 |
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 |
11 | import com.aldebaran.qi.sdk.QiContext;
12 | import com.aldebaran.qi.sdk.QiSDK;
13 | import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
14 | import com.aldebaran.qi.sdk.builder.SayBuilder;
15 | import com.aldebaran.qi.sdk.design.activity.RobotActivity;
16 | import com.aldebaran.qi.sdk.object.conversation.Say;
17 | import com.softbankrobotics.sample.returntomapframe.R;
18 | import com.softbankrobotics.sample.returntomapframe.menu.MenuActivity;
19 |
20 | import androidx.annotation.NonNull;
21 | import butterknife.ButterKnife;
22 | import butterknife.OnClick;
23 |
24 | /**
25 | * The introduction Activity.
26 | */
27 | public class IntroductionActivity extends RobotActivity implements RobotLifecycleCallbacks {
28 |
29 | @NonNull
30 | private static final String TAG = "IntroductionActivity";
31 |
32 | @Override
33 | protected void onCreate(Bundle savedInstanceState) {
34 | super.onCreate(savedInstanceState);
35 |
36 | setContentView(R.layout.activity_introduction);
37 | ButterKnife.bind(this);
38 |
39 | QiSDK.register(this, this);
40 | }
41 |
42 | @Override
43 | protected void onDestroy() {
44 | QiSDK.unregister(this, this);
45 | super.onDestroy();
46 | }
47 |
48 | @Override
49 | public void onRobotFocusGained(QiContext qiContext) {
50 | Say say = SayBuilder.with(qiContext)
51 | .withResource(R.string.intro_speech)
52 | .build();
53 |
54 | say.async().run()
55 | .andThenConsume(ignored -> goToMenu());
56 | }
57 |
58 | @Override
59 | public void onRobotFocusLost() {
60 | // Not used.
61 | }
62 |
63 | @Override
64 | public void onRobotFocusRefused(String reason) {
65 | Log.e(TAG, "onRobotFocusRefused: " + reason);
66 | }
67 |
68 | @OnClick(R.id.closeButton)
69 | public void onCloseClicked() {
70 | finishAffinity();
71 | }
72 |
73 | private void goToMenu() {
74 | runOnUiThread(() -> {
75 | Intent intent = new Intent(this, MenuActivity.class);
76 | startActivity(intent);
77 | finish();
78 | });
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
23 |
24 |
28 |
29 |
33 |
34 |
46 |
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Android
2 |
3 |
4 | # Built application files
5 | *.apk
6 | *.ap_
7 | *.aab
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Generated files
13 | bin/
14 | gen/
15 | out/
16 |
17 | # Gradle files
18 | .gradle/
19 | build/
20 | .gradletasknamecache
21 | gradle-app.setting
22 |
23 | # Local configuration file (sdk path, etc)
24 | local.properties
25 | gradle.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Android Studio Navigation editor temp files
31 | .navigation/
32 |
33 | # Android Studio captures folder
34 | captures/
35 |
36 | # IntelliJ
37 | *.iml
38 | .idea/
39 | .idea_modules/
40 |
41 | # Keystore files
42 | # Uncomment the following lines if you do not want to check your keystore files in.
43 | #*.jks
44 | #*.keystore
45 |
46 | # External native build folder generated in Android Studio 2.2 and later
47 | .externalNativeBuild
48 |
49 | # Google Services (e.g. APIs or Firebase)
50 | google-services.json
51 |
52 | # Freeline
53 | freeline.py
54 | freeline/
55 | freeline_project_description.json
56 |
57 | # fastlane
58 | fastlane/report.xml
59 | fastlane/Preview.html
60 | fastlane/screenshots
61 | fastlane/test_output
62 | fastlane/readme.md
63 |
64 | # Crashlytics plugin (for Android Studio and IntelliJ)
65 | com_crashlytics_export_strings.xml
66 | crashlytics.properties
67 | crashlytics-build.properties
68 | fabric.properties
69 |
70 |
71 |
72 | # Java & Kotlin
73 |
74 |
75 | # Compiled class file
76 | *.class
77 |
78 | # Log file
79 | *.log
80 |
81 | # BlueJ files
82 | *.ctxt
83 |
84 | # Mobile Tools for Java (J2ME)
85 | .mtj.tmp/
86 |
87 | # Package Files #
88 | *.jar
89 | *.war
90 | *.nar
91 | *.ear
92 | *.zip
93 | *.tar.gz
94 | *.rar
95 |
96 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
97 | !gradle-wrapper.jar
98 |
99 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
100 | hs_err_pid*
101 |
102 |
103 |
104 | # Others
105 |
106 |
107 | # Mac OS
108 | .DS_Store
109 | .AppleDouble
110 | .LSOverride
111 |
112 | # CMake
113 | cmake-build-debug/
114 | cmake-build-release/
115 |
116 | # File-based project format
117 | *.iws
118 |
119 | # JIRA plugin
120 | atlassian-ide-plugin.xml
121 |
122 | # Files that might appear in the root of a volume
123 | .DocumentRevisions-V100
124 | .fseventsd
125 | .Spotlight-V100
126 | .TemporaryItems
127 | .Trashes
128 | .VolumeIcon.icns
129 | .com.apple.timemachine.donotpresent
130 |
131 | # Directories potentially created on remote AFP share
132 | .AppleDB
133 | .AppleDesktop
134 | Network Trash Folder
135 | Temporary Items
136 | .apdisk
137 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/gotoorigin/GoToOriginMachine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.gotoorigin;
6 |
7 | import androidx.annotation.NonNull;
8 | import io.reactivex.Observable;
9 | import io.reactivex.subjects.BehaviorSubject;
10 |
11 | /**
12 | * The state machine for {@link GoToOriginScreen}.
13 | */
14 | class GoToOriginMachine {
15 |
16 | @NonNull
17 | private final BehaviorSubject subject = BehaviorSubject.createDefault(GoToOriginState.IDLE);
18 |
19 | /**
20 | * Post an event to the machine.
21 | *
22 | * @param event the event
23 | */
24 | void post(@NonNull GoToOriginEvent event) {
25 | GoToOriginState currentState = subject.getValue();
26 | if (currentState == null) {
27 | throw new IllegalStateException("GoToOriginMachine must have a GoToOriginState to be able to handle a GoToOriginEvent.");
28 | }
29 |
30 | GoToOriginState newState = reduce(currentState, event);
31 | subject.onNext(newState);
32 | }
33 |
34 | /**
35 | * Provide the current {@link GoToOriginState}.
36 | *
37 | * @return The current {@link GoToOriginState}.
38 | */
39 | @NonNull
40 | Observable goToOriginState() {
41 | return subject.distinctUntilChanged();
42 | }
43 |
44 | @NonNull
45 | private GoToOriginState reduce(@NonNull GoToOriginState currentState, @NonNull GoToOriginEvent event) {
46 | switch (event) {
47 | case START:
48 | if (currentState.equals(GoToOriginState.IDLE)) {
49 | return GoToOriginState.BRIEFING;
50 | }
51 | break;
52 | case STOP:
53 | return GoToOriginState.IDLE;
54 | case START_GO_TO_ORIGIN:
55 | if (currentState.equals(GoToOriginState.BRIEFING) || currentState.equals(GoToOriginState.ERROR)) {
56 | return GoToOriginState.MOVING;
57 | }
58 | break;
59 | case GO_TO_ORIGIN_SUCCEEDED:
60 | if (currentState.equals(GoToOriginState.MOVING)) {
61 | return GoToOriginState.SUCCESS;
62 | }
63 | break;
64 | case GO_TO_ORIGIN_FAILED:
65 | if (currentState.equals(GoToOriginState.MOVING)) {
66 | return GoToOriginState.ERROR;
67 | }
68 | break;
69 | case SUCCESS_CONFIRMED:
70 | if (currentState.equals(GoToOriginState.SUCCESS)) {
71 | return GoToOriginState.END;
72 | }
73 | break;
74 | }
75 |
76 | return currentState;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/ScreenMachine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | import androidx.annotation.NonNull;
8 | import io.reactivex.Observable;
9 | import io.reactivex.subjects.BehaviorSubject;
10 |
11 | /**
12 | * The state machine for screens.
13 | */
14 | public class ScreenMachine {
15 |
16 | @NonNull
17 | private final BehaviorSubject subject = BehaviorSubject.createDefault(ScreenState.NONE);
18 |
19 | /**
20 | * Post an event to the machine.
21 | *
22 | * @param event the event
23 | */
24 | public void post(@NonNull ScreenEvent event) {
25 | ScreenState currentState = subject.getValue();
26 | if (currentState == null) {
27 | throw new IllegalStateException("ScreenMachine must have a ScreenState to be able to handle a ScreenEvent.");
28 | }
29 |
30 | ScreenState newState = reduce(currentState, event);
31 | subject.onNext(newState);
32 | }
33 |
34 | /**
35 | * Provide the current {@link ScreenState}.
36 | *
37 | * @return The current {@link ScreenState}.
38 | */
39 | @NonNull
40 | Observable screenState() {
41 | return subject.distinctUntilChanged();
42 | }
43 |
44 | @NonNull
45 | private ScreenState reduce(@NonNull ScreenState currentState, @NonNull ScreenEvent event) {
46 | switch (event) {
47 | case FOCUS_GAINED:
48 | if (currentState.equals(ScreenState.NONE)) {
49 | return ScreenState.LOCALIZATION_MENU;
50 | }
51 | break;
52 | case FOCUS_LOST:
53 | return ScreenState.NONE;
54 | case BACK:
55 | switch (currentState) {
56 | case LOCALIZATION_MENU:
57 | return ScreenState.END;
58 | case LOCALIZE:
59 | return ScreenState.LOCALIZATION_MENU;
60 | case GO_TO_ORIGIN:
61 | return ScreenState.LOCALIZATION_MENU;
62 | }
63 | break;
64 | case LOCALIZE_SELECTED:
65 | if (currentState.equals(ScreenState.LOCALIZATION_MENU)) {
66 | return ScreenState.LOCALIZE;
67 | }
68 | break;
69 | case GO_TO_ORIGIN_SELECTED:
70 | if (currentState.equals(ScreenState.LOCALIZATION_MENU)) {
71 | return ScreenState.GO_TO_ORIGIN;
72 | }
73 | break;
74 | case LOCALIZE_END:
75 | if (currentState.equals(ScreenState.LOCALIZE)) {
76 | return ScreenState.LOCALIZATION_MENU;
77 | }
78 | break;
79 | case GO_TO_ORIGIN_END:
80 | if (currentState.equals(ScreenState.GO_TO_ORIGIN)) {
81 | return ScreenState.LOCALIZATION_MENU;
82 | }
83 | break;
84 | }
85 |
86 | return currentState;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/mapping/MappingMachine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.mapping;
6 |
7 | import androidx.annotation.NonNull;
8 | import io.reactivex.Observable;
9 | import io.reactivex.subjects.BehaviorSubject;
10 |
11 | /**
12 | * The state machine for {@link MappingActivity}.
13 | */
14 | class MappingMachine {
15 |
16 | @NonNull
17 | private final BehaviorSubject subject = BehaviorSubject.createDefault(MappingState.IDLE);
18 |
19 | /**
20 | * Post an event to the machine.
21 | *
22 | * @param event the event
23 | */
24 | void post(@NonNull MappingEvent event) {
25 | MappingState currentState = subject.getValue();
26 | if (currentState == null) {
27 | throw new IllegalStateException("MappingMachine must have a MappingState to be able to handle a MappingEvent.");
28 | }
29 |
30 | MappingState newState = reduce(currentState, event);
31 | subject.onNext(newState);
32 | }
33 |
34 | /**
35 | * Provide the current {@link MappingState}.
36 | *
37 | * @return The current {@link MappingState}.
38 | */
39 | @NonNull
40 | Observable mappingState() {
41 | return subject.distinctUntilChanged();
42 | }
43 |
44 | @NonNull
45 | private MappingState reduce(@NonNull MappingState currentState, @NonNull MappingEvent event) {
46 | switch (event) {
47 | case FOCUS_GAINED:
48 | if (currentState.equals(MappingState.IDLE)) {
49 | return MappingState.BRIEFING;
50 | }
51 | break;
52 | case FOCUS_LOST:
53 | return MappingState.IDLE;
54 | case START_MAPPING:
55 | if (currentState.equals(MappingState.BRIEFING) || currentState.equals(MappingState.ERROR)) {
56 | return MappingState.ADVICES;
57 | }
58 | break;
59 | case ADVICES_ENDED:
60 | if (currentState.equals(MappingState.ADVICES)) {
61 | return MappingState.MAPPING;
62 | }
63 | break;
64 | case MAPPING_SUCCEEDED:
65 | if (currentState.equals(MappingState.MAPPING)) {
66 | return MappingState.SAVING_MAP;
67 | }
68 | break;
69 | case MAPPING_FAILED:
70 | if (currentState.equals(MappingState.MAPPING)) {
71 | return MappingState.ERROR;
72 | }
73 | break;
74 | case SAVING_MAP_SUCCEEDED:
75 | return MappingState.SUCCESS;
76 | case SAVING_MAP_FAILED:
77 | if (currentState.equals(MappingState.SAVING_MAP)) {
78 | return MappingState.ERROR;
79 | }
80 | break;
81 | case SUCCESS_CONFIRMED:
82 | if (currentState.equals(MappingState.SUCCESS)) {
83 | return MappingState.END;
84 | }
85 | break;
86 | }
87 |
88 | return currentState;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localizationmenu/LocalizationMenuScreen.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localizationmenu;
6 |
7 | import com.aldebaran.qi.Future;
8 | import com.aldebaran.qi.sdk.QiContext;
9 | import com.softbankrobotics.sample.returntomapframe.R;
10 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizationActivity;
11 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizeManager;
12 | import com.softbankrobotics.sample.returntomapframe.localization.Screen;
13 | import com.softbankrobotics.sample.returntomapframe.localization.ScreenEvent;
14 |
15 | import androidx.annotation.NonNull;
16 | import androidx.annotation.Nullable;
17 |
18 | /**
19 | * The localization menu screen.
20 | */
21 | public class LocalizationMenuScreen implements Screen {
22 |
23 | @NonNull
24 | private final LocalizationActivity activity;
25 | @NonNull
26 | private final LocalizationMenuRobot robot;
27 | @Nullable
28 | private LocalizationMenuFragment localizationMenuFragment;
29 |
30 | public LocalizationMenuScreen(@NonNull LocalizationActivity activity, @NonNull LocalizeManager localizeManager) {
31 | this.activity = activity;
32 | this.robot = new LocalizationMenuRobot(this, localizeManager);
33 | }
34 |
35 | @Override
36 | public void start(@NonNull QiContext qiContext) {
37 | activity.setNavigationTitle(R.string.localization_menu_title);
38 |
39 | localizationMenuFragment = LocalizationMenuFragment.newInstance(this);
40 | activity.showFragment(localizationMenuFragment);
41 | robot.startDiscussion(qiContext);
42 | }
43 |
44 | @NonNull
45 | @Override
46 | public Future stop() {
47 | return robot.stop();
48 | }
49 |
50 | void enableGoToOrigin() {
51 | if (localizationMenuFragment != null) {
52 | localizationMenuFragment.enableGoToOrigin();
53 | }
54 | }
55 |
56 | void disableChoices() {
57 | if (localizationMenuFragment != null) {
58 | localizationMenuFragment.disableChoices();
59 | }
60 | }
61 |
62 | void selectLocalize() {
63 | if (localizationMenuFragment != null) {
64 | localizationMenuFragment.selectLocalize();
65 | }
66 | }
67 |
68 | void selectGoToOrigin() {
69 | if (localizationMenuFragment != null) {
70 | localizationMenuFragment.selectGoToOrigin();
71 | }
72 | }
73 |
74 | void onLocalizeSelected() {
75 | activity.getScreenMachine().post(ScreenEvent.LOCALIZE_SELECTED);
76 | }
77 |
78 | void onGoToOriginSelected() {
79 | activity.getScreenMachine().post(ScreenEvent.GO_TO_ORIGIN_SELECTED);
80 | }
81 |
82 | void onLocalizeClicked() {
83 | if (localizationMenuFragment != null) {
84 | localizationMenuFragment.disableChoices();
85 | }
86 | robot.goToLocalizeBookmark();
87 | }
88 |
89 | void onGoToInitialPositionClicked() {
90 | if (localizationMenuFragment != null) {
91 | localizationMenuFragment.disableChoices();
92 | }
93 | robot.goToGoToInitialPositionBookmark();
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_go_to_origin.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
34 |
35 |
48 |
49 |
59 |
60 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_localize.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
34 |
35 |
48 |
49 |
59 |
60 |
71 |
72 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localizationmenu/LocalizationMenuFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localizationmenu;
6 |
7 | import android.os.Bundle;
8 | import android.view.LayoutInflater;
9 | import android.view.View;
10 | import android.view.ViewGroup;
11 | import android.widget.RadioButton;
12 |
13 | import com.softbankrobotics.sample.returntomapframe.R;
14 |
15 | import androidx.annotation.NonNull;
16 | import androidx.annotation.Nullable;
17 | import androidx.fragment.app.Fragment;
18 | import androidx.fragment.app.FragmentActivity;
19 | import butterknife.BindView;
20 | import butterknife.ButterKnife;
21 | import butterknife.OnClick;
22 | import butterknife.Unbinder;
23 |
24 | /**
25 | * The localization menu Fragment.
26 | */
27 | public class LocalizationMenuFragment extends Fragment {
28 |
29 | @Nullable
30 | private LocalizationMenuScreen screen;
31 |
32 | @Nullable
33 | private Unbinder unbinder;
34 |
35 | @BindView(R.id.localizeButton)
36 | RadioButton localizeButton;
37 |
38 | @BindView(R.id.goToInitialPositionButton)
39 | RadioButton goToInitialPositionButton;
40 |
41 | @Override
42 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
43 | Bundle savedInstanceState) {
44 | View view = inflater.inflate(R.layout.fragment_localization_menu, container, false);
45 | unbinder = ButterKnife.bind(this, view);
46 | return view;
47 | }
48 |
49 | @Override
50 | public void onResume() {
51 | super.onResume();
52 |
53 | localizeButton.setChecked(false);
54 | goToInitialPositionButton.setChecked(false);
55 |
56 | localizeButton.setEnabled(true);
57 | goToInitialPositionButton.setEnabled(false);
58 | }
59 |
60 | @Override
61 | public void onDestroyView() {
62 | if (unbinder != null) {
63 | unbinder.unbind();
64 | }
65 | super.onDestroyView();
66 | }
67 |
68 | @OnClick(R.id.localizeButton)
69 | public void onClickLocalize() {
70 | if (screen != null) {
71 | screen.onLocalizeClicked();
72 | }
73 | }
74 |
75 | @OnClick(R.id.goToInitialPositionButton)
76 | public void onClickGoToInitialPosition() {
77 | if (screen != null) {
78 | screen.onGoToInitialPositionClicked();
79 | }
80 | }
81 |
82 | @NonNull
83 | static LocalizationMenuFragment newInstance(@NonNull LocalizationMenuScreen screen) {
84 | LocalizationMenuFragment fragment = new LocalizationMenuFragment();
85 | fragment.screen = screen;
86 | return fragment;
87 | }
88 |
89 | void enableGoToOrigin() {
90 | runOnUiThread(() -> goToInitialPositionButton.setEnabled(true));
91 | }
92 |
93 | void disableChoices() {
94 | runOnUiThread(() -> {
95 | localizeButton.setEnabled(false);
96 | goToInitialPositionButton.setEnabled(false);
97 | });
98 | }
99 |
100 | void selectLocalize() {
101 | runOnUiThread(() -> localizeButton.setChecked(true));
102 | }
103 |
104 | void selectGoToOrigin() {
105 | runOnUiThread(() -> goToInitialPositionButton.setChecked(true));
106 | }
107 |
108 | private void runOnUiThread(@NonNull Runnable runnable) {
109 | FragmentActivity activity = getActivity();
110 | if (activity != null) {
111 | activity.runOnUiThread(runnable);
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localize/LocalizeMachine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localize;
6 |
7 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizeManager;
8 |
9 | import androidx.annotation.NonNull;
10 | import io.reactivex.Observable;
11 | import io.reactivex.subjects.BehaviorSubject;
12 |
13 | /**
14 | * The state machine for {@link LocalizeScreen}.
15 | */
16 | class LocalizeMachine {
17 |
18 | @NonNull
19 | private final BehaviorSubject subject = BehaviorSubject.createDefault(LocalizeState.IDLE);
20 |
21 | @NonNull
22 | private final LocalizeManager localizeManager;
23 |
24 | LocalizeMachine(@NonNull LocalizeManager localizeManager) {
25 | this.localizeManager = localizeManager;
26 | }
27 |
28 | /**
29 | * Post an event to the machine.
30 | *
31 | * @param event the event
32 | */
33 | void post(@NonNull LocalizeEvent event) {
34 | LocalizeState currentState = subject.getValue();
35 | if (currentState == null) {
36 | throw new IllegalStateException("LocalizeMachine must have a LocalizeState to be able to handle a LocalizeEvent.");
37 | }
38 |
39 | LocalizeState newState = reduce(currentState, event);
40 | subject.onNext(newState);
41 | }
42 |
43 | /**
44 | * Provide the current {@link LocalizeState}.
45 | *
46 | * @return The current {@link LocalizeState}.
47 | */
48 | @NonNull
49 | Observable localizeState() {
50 | return subject.distinctUntilChanged();
51 | }
52 |
53 | @NonNull
54 | private LocalizeState reduce(@NonNull LocalizeState currentState, @NonNull LocalizeEvent event) {
55 | switch (event) {
56 | case START:
57 | if (currentState.equals(LocalizeState.IDLE)) {
58 | return LocalizeState.BRIEFING;
59 | }
60 | break;
61 | case STOP:
62 | return LocalizeState.IDLE;
63 | case START_LOCALIZE:
64 | if (currentState.equals(LocalizeState.BRIEFING) || currentState.equals(LocalizeState.ERROR)) {
65 | return LocalizeState.ADVICES;
66 | }
67 | break;
68 | case ADVICES_ENDED:
69 | if (currentState.equals(LocalizeState.ADVICES)) {
70 | if (localizeManager.mapIsLoaded()) {
71 | return LocalizeState.LOCALIZING;
72 | }
73 | return LocalizeState.LOADING_MAP;
74 | }
75 | break;
76 | case LOADING_MAP_SUCCEEDED:
77 | if (currentState.equals(LocalizeState.LOADING_MAP)) {
78 | return LocalizeState.LOCALIZING;
79 | }
80 | break;
81 | case LOADING_MAP_FAILED:
82 | if (currentState.equals(LocalizeState.LOADING_MAP)) {
83 | return LocalizeState.ERROR;
84 | }
85 | break;
86 | case LOCALIZE_SUCCEEDED:
87 | if (currentState.equals(LocalizeState.LOCALIZING)) {
88 | return LocalizeState.SUCCESS;
89 | }
90 | break;
91 | case LOCALIZE_FAILED:
92 | if (currentState.equals(LocalizeState.LOCALIZING)) {
93 | return LocalizeState.ERROR;
94 | }
95 | break;
96 | case SUCCESS_CONFIRMED:
97 | if (currentState.equals(LocalizeState.SUCCESS)) {
98 | return LocalizeState.END;
99 | }
100 | break;
101 | }
102 |
103 | return currentState;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/core/MapManager.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.core
6 |
7 | import android.content.Context
8 | import android.util.Log
9 | import com.aldebaran.qi.Future
10 | import com.aldebaran.qi.sdk.QiContext
11 | import com.aldebaran.qi.sdk.`object`.actuation.ExplorationMap
12 | import com.aldebaran.qi.sdk.`object`.streamablebuffer.StreamableBuffer
13 | import com.aldebaran.qi.sdk.`object`.streamablebuffer.StreamableBufferFactory
14 | import com.aldebaran.qi.sdk.builder.ExplorationMapBuilder
15 | import com.aldebaran.qi.sdk.util.copyToStream
16 | import java.io.File
17 | import java.io.RandomAccessFile
18 | import java.nio.ByteBuffer
19 |
20 | /**
21 | * Manager that provides and saves the [ExplorationMap].
22 | */
23 | object MapManager {
24 |
25 | private const val TAG = "MapManager"
26 | private const val MAP_FILENAME = "map.txt"
27 |
28 | // The cached map.
29 | private var explorationMap: ExplorationMap? = null
30 |
31 | /**
32 | * Save the specified map to a file.
33 | *
34 | * @param context the context
35 | * @param map the map to save
36 | * @return A [Future] wrapping the operation.
37 | */
38 | @JvmStatic
39 | fun saveMap(context: Context, map: ExplorationMap): Future {
40 | // Cache the map.
41 | this.explorationMap = map
42 |
43 | // Serialize the map and write it to the file.
44 | Log.d(TAG, "Serializing map...")
45 | return map.async().serializeAsStreamableBuffer()
46 | .andThenConsume { streamableBuffer: StreamableBuffer ->
47 | Log.d(TAG, "Map serialized successfully")
48 | writeMapToFile(context, streamableBuffer)
49 | }
50 | }
51 |
52 | /**
53 | * Indicate if there is an existing map or not.
54 | *
55 | * @param context the context
56 | * @return `true` if there is a map, `false` otherwise.
57 | */
58 | @JvmStatic
59 | fun hasMap(context: Context): Boolean {
60 | // If cached map available, return true directly.
61 | if (this.explorationMap != null) {
62 | return true
63 | }
64 |
65 | // Check if the map file exists.
66 | val mapFile = File(context.filesDir, MAP_FILENAME)
67 | return mapFile.exists()
68 | }
69 |
70 | /**
71 | * Provide the map.
72 | *
73 | * @param qiContext the qiContext
74 | * @return A [Future] wrapping the operation.
75 | */
76 | @JvmStatic
77 | fun retrieveMap(qiContext: QiContext): Future {
78 | // If cached map available, return it directly.
79 | val explorationMap = this.explorationMap
80 | return if (explorationMap != null) {
81 | Future.of(explorationMap)
82 | } else {
83 | Future.of(qiContext)
84 | .andThenApply { context ->
85 | val mapFile = File(context.filesDir, MAP_FILENAME)
86 | StreamableBufferFactory.fromFile(mapFile)
87 | }
88 | .andThenApply {
89 | ExplorationMapBuilder.with(qiContext)
90 | .withStreamableBuffer(it)
91 | .build()
92 | // Cache the map.
93 | .also { explorationMap -> this.explorationMap = explorationMap }
94 | }
95 | }
96 |
97 | // Read the file and create the ExplorationMap.
98 | }
99 |
100 | private fun writeMapToFile(context: Context, streamableBuffer: StreamableBuffer) {
101 | val mapFile = File(context.filesDir, MAP_FILENAME)
102 | mapFile.outputStream().use {
103 | streamableBuffer.copyToStream(it)
104 | }
105 | }
106 |
107 | private fun StreamableBufferFactory.fromFile(file: File): StreamableBuffer {
108 | return fromFunction(file.length()) { offset, size ->
109 | RandomAccessFile(file, "r").use {
110 | val byteArray = ByteArray(size.toInt())
111 | it.seek(offset)
112 | it.read(byteArray)
113 |
114 | ByteBuffer.wrap(byteArray)
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Return To MapFrame
3 |
4 |
5 | Welcome, dear developer. In this sample, you will see how I can map my environment to know where I am. And then, I will be able to relocalize myself.
6 |
7 |
8 | \"Create a new map\"
9 | \"Use saved map\"
10 | We can create a new map and we will be able to use it later.
11 | Do you want to create a new map or to use a previously saved map?
12 |
13 |
14 | Mapping in progress…
15 | Saving map…
16 | I will now map my environment. Please be sure to be at least at 3 meters away from me while I scan the place.
17 | I will now save the map.
18 | Perfect! I\'ve created a map. But we are not done! Because this is a sample, you need now to ask me to localize myself. Let\'s go back to the main menu and continue the procedure with the localization.
19 | Map creation
20 |
21 |
22 | Use saved map
23 | \"Localize yourself\"
24 | \"Go to your initial position\"
25 | I can localize myself and go to my initial position later.
26 | Based on the map you already saved, do you want me to localize myself or to go to my initial position?
27 |
28 |
29 | Localization
30 | Loading map…
31 | Localization in progress…
32 | Please be sure to be at least at 3 meters away from me while I check if I\'m at the right place.
33 | OK, I know where I am.
34 |
35 |
36 | Go to original position
37 | First move me, then press Go.
38 | Moving…
39 | First, open my back hatch and move me. Then, once I am in the desired position, close my back hatch and press Go to make me go back to my initial position.
40 | Oops, something went wrong. Please check there is nothing on my way avoiding me to go back to my initial position. Then try again.
41 | Awesome! I\'m back to my initial position!
42 | Go
43 |
44 |
45 | Background image
46 | Close button
47 | Back button
48 | Warning image
49 | Success image
50 |
51 |
52 | lottie/splashy_loader.json
53 |
54 |
55 | Start
56 | Make sure my back hatch is closed
57 | Please stay away from me until I\'m done!
58 | Something is wrong
59 | Successfully done
60 | Make sure I am not charging so I can move. Please double check if my back hatch is closed then press start.
61 | 5, 4, 3, 2, 1.
62 | Oops, something went wrong. Please check if there is nothing around me avoiding me to turn and scan, then try again.
63 |
64 |
65 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_mapping.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
20 |
21 |
34 |
35 |
48 |
49 |
59 |
60 |
71 |
72 |
82 |
83 |
93 |
94 |
107 |
108 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/gotoorigin/GoToOriginRobot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.gotoorigin;
6 |
7 | import android.util.Log;
8 |
9 | import com.aldebaran.qi.Future;
10 | import com.aldebaran.qi.sdk.QiContext;
11 | import com.aldebaran.qi.sdk.builder.GoToBuilder;
12 | import com.aldebaran.qi.sdk.builder.SayBuilder;
13 | import com.softbankrobotics.sample.returntomapframe.R;
14 | import com.softbankrobotics.sample.returntomapframe.localization.Robot;
15 | import com.softbankrobotics.sample.returntomapframe.utils.FutureCancellations;
16 |
17 | import androidx.annotation.NonNull;
18 | import androidx.annotation.Nullable;
19 | import androidx.annotation.StringRes;
20 | import io.reactivex.disposables.Disposable;
21 | import io.reactivex.schedulers.Schedulers;
22 |
23 | /**
24 | * The robot for {@link GoToOriginScreen}.
25 | */
26 | class GoToOriginRobot implements Robot {
27 |
28 | @NonNull
29 | private static final String TAG = "GoToOriginRobot";
30 |
31 | @NonNull
32 | private final GoToOriginMachine machine;
33 |
34 | @Nullable
35 | private QiContext qiContext;
36 |
37 | @Nullable
38 | private Disposable disposable;
39 |
40 | @Nullable
41 | private Future speech;
42 | @Nullable
43 | private Future movement;
44 |
45 | GoToOriginRobot(@NonNull GoToOriginMachine machine) {
46 | this.machine = machine;
47 | }
48 |
49 | @NonNull
50 | @Override
51 | public Future stop() {
52 | machine.post(GoToOriginEvent.STOP);
53 |
54 | if (disposable != null && !disposable.isDisposed()) {
55 | disposable.dispose();
56 | }
57 |
58 | this.qiContext = null;
59 |
60 | return FutureCancellations.cancel(speech);
61 | }
62 |
63 | public void start(@NonNull QiContext qiContext) {
64 | this.qiContext = qiContext;
65 | machine.post(GoToOriginEvent.START);
66 |
67 | disposable = machine.goToOriginState()
68 | .subscribeOn(Schedulers.io())
69 | .observeOn(Schedulers.io())
70 | .subscribe(this::onGoToOriginStateChanged);
71 | }
72 |
73 | @NonNull
74 | private Future say(@StringRes int resId) {
75 | return FutureCancellations.cancel(speech)
76 | .andThenCompose(ignored -> {
77 | if (qiContext == null) {
78 | throw new IllegalStateException("qiContext is null");
79 | }
80 |
81 | Future newSpeech = SayBuilder.with(qiContext)
82 | .withText(qiContext.getString(resId))
83 | .buildAsync()
84 | .andThenCompose(say -> say.async().run());
85 |
86 | speech = newSpeech;
87 | return newSpeech;
88 | });
89 | }
90 |
91 | private void goToMapFrame() {
92 | if (qiContext == null) {
93 | Log.e(TAG, "Error while going to map frame: qiContext is null");
94 | machine.post(GoToOriginEvent.GO_TO_ORIGIN_FAILED);
95 | return;
96 | }
97 |
98 | // Retrieve the map frame and go to it.
99 | movement = qiContext.getMapping().async().mapFrame()
100 | .andThenCompose(mapFrame -> GoToBuilder.with(qiContext).withFrame(mapFrame).buildAsync())
101 | .andThenCompose(goTo -> goTo.async().run())
102 | .thenConsume(future -> {
103 | if (future.isSuccess()) {
104 | Log.d(TAG, "Map frame reached successfully");
105 | machine.post(GoToOriginEvent.GO_TO_ORIGIN_SUCCEEDED);
106 | } else if (future.hasError()) {
107 | Log.e(TAG, "Error while going to map frame", future.getError());
108 | machine.post(GoToOriginEvent.GO_TO_ORIGIN_FAILED);
109 | }
110 | });
111 | }
112 |
113 | @NonNull
114 | private Future cancelCurrentActions() {
115 | return FutureCancellations.cancel(speech, movement);
116 | }
117 |
118 | private void onGoToOriginStateChanged(@NonNull GoToOriginState goToOriginState) {
119 | Log.d(TAG, "onGoToOriginStateChanged: " + goToOriginState);
120 |
121 | switch (goToOriginState) {
122 | case IDLE:
123 | case END:
124 | cancelCurrentActions();
125 | break;
126 | case BRIEFING:
127 | cancelCurrentActions()
128 | .andThenCompose(ignored -> say(R.string.go_to_origin_briefing_speech));
129 | break;
130 | case MOVING:
131 | cancelCurrentActions()
132 | .andThenConsume(ignored -> goToMapFrame());
133 | break;
134 | case ERROR:
135 | cancelCurrentActions()
136 | .andThenCompose(ignored -> say(R.string.go_to_origin_error_speech));
137 | break;
138 | case SUCCESS:
139 | cancelCurrentActions()
140 | .andThenCompose(ignored -> say(R.string.go_to_origin_success_speech))
141 | .andThenConsume(ignored -> machine.post(GoToOriginEvent.SUCCESS_CONFIRMED));
142 | break;
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localize/LocalizeRobot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localize;
6 |
7 | import android.util.Log;
8 |
9 | import com.aldebaran.qi.Future;
10 | import com.aldebaran.qi.sdk.QiContext;
11 | import com.aldebaran.qi.sdk.builder.SayBuilder;
12 | import com.softbankrobotics.sample.returntomapframe.R;
13 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizeManager;
14 | import com.softbankrobotics.sample.returntomapframe.localization.Robot;
15 | import com.softbankrobotics.sample.returntomapframe.utils.FutureCancellations;
16 |
17 | import androidx.annotation.NonNull;
18 | import androidx.annotation.Nullable;
19 | import androidx.annotation.StringRes;
20 | import io.reactivex.disposables.Disposable;
21 | import io.reactivex.schedulers.Schedulers;
22 |
23 | /**
24 | * The robot for {@link LocalizeScreen}.
25 | */
26 | class LocalizeRobot implements Robot {
27 |
28 | @NonNull
29 | private static final String TAG = "LocalizeRobot";
30 |
31 | @NonNull
32 | private final LocalizeMachine machine;
33 | @NonNull
34 | private final LocalizeManager localizeManager;
35 |
36 | @Nullable
37 | private QiContext qiContext;
38 |
39 | @Nullable
40 | private Disposable disposable;
41 |
42 | @Nullable
43 | private Future speech;
44 |
45 | LocalizeRobot(@NonNull LocalizeMachine machine, @NonNull LocalizeManager localizeManager) {
46 | this.machine = machine;
47 | this.localizeManager = localizeManager;
48 | }
49 |
50 | @NonNull
51 | @Override
52 | public Future stop() {
53 | machine.post(LocalizeEvent.STOP);
54 |
55 | if (disposable != null && !disposable.isDisposed()) {
56 | disposable.dispose();
57 | }
58 |
59 | this.qiContext = null;
60 |
61 | return FutureCancellations.cancel(speech);
62 | }
63 |
64 | void start(@NonNull QiContext qiContext) {
65 | this.qiContext = qiContext;
66 | machine.post(LocalizeEvent.START);
67 |
68 | disposable = machine.localizeState()
69 | .subscribeOn(Schedulers.io())
70 | .observeOn(Schedulers.io())
71 | .subscribe(this::onLocalizeStateChanged);
72 | }
73 |
74 | @NonNull
75 | private Future say(@StringRes int resId) {
76 | return FutureCancellations.cancel(speech)
77 | .andThenCompose(ignored -> {
78 | if (qiContext == null) {
79 | throw new IllegalStateException("qiContext is null");
80 | }
81 |
82 | Future newSpeech = SayBuilder.with(qiContext)
83 | .withText(qiContext.getString(resId))
84 | .buildAsync()
85 | .andThenCompose(say -> say.async().run());
86 |
87 | speech = newSpeech;
88 | return newSpeech;
89 | });
90 | }
91 |
92 | private void onLocalizeStateChanged(@NonNull LocalizeState localizeState) {
93 | Log.d(TAG, "onLocalizeStateChanged: " + localizeState);
94 |
95 | switch (localizeState) {
96 | case IDLE:
97 | case END:
98 | FutureCancellations.cancel(speech);
99 | break;
100 | case BRIEFING:
101 | say(R.string.briefing_speech);
102 | break;
103 | case ADVICES:
104 | say(R.string.localize_advices_speech)
105 | .andThenCompose(ignored -> say(R.string.countdown_speech))
106 | .andThenConsume(ignored -> machine.post(LocalizeEvent.ADVICES_ENDED));
107 | break;
108 | case LOADING_MAP:
109 | if (qiContext == null) {
110 | machine.post(LocalizeEvent.LOADING_MAP_FAILED);
111 | return;
112 | }
113 |
114 | localizeManager.loadMap(qiContext)
115 | .thenConsume(future -> {
116 | if (future.isSuccess()) {
117 | machine.post(LocalizeEvent.LOADING_MAP_SUCCEEDED);
118 | } else if (future.hasError()) {
119 | machine.post(LocalizeEvent.LOADING_MAP_FAILED);
120 | }
121 | });
122 | break;
123 | case LOCALIZING:
124 | if (qiContext == null) {
125 | machine.post(LocalizeEvent.LOCALIZE_FAILED);
126 | return;
127 | }
128 |
129 | localizeManager.localizeRobot()
130 | .thenConsume(future -> {
131 | if (future.isSuccess()) {
132 | machine.post(LocalizeEvent.LOCALIZE_SUCCEEDED);
133 | } else if (future.hasError()) {
134 | machine.post(LocalizeEvent.LOCALIZE_FAILED);
135 | }
136 | });
137 | break;
138 | case ERROR:
139 | say(R.string.error_speech);
140 | break;
141 | case SUCCESS:
142 | say(R.string.localize_success_speech)
143 | .andThenConsume(ignored -> machine.post(LocalizeEvent.SUCCESS_CONFIRMED));
144 | break;
145 | }
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/LocalizeManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | import android.util.Log;
8 |
9 | import com.aldebaran.qi.Future;
10 | import com.aldebaran.qi.Promise;
11 | import com.aldebaran.qi.sdk.QiContext;
12 | import com.aldebaran.qi.sdk.builder.LocalizeBuilder;
13 | import com.aldebaran.qi.sdk.object.actuation.LocalizationStatus;
14 | import com.aldebaran.qi.sdk.object.actuation.Localize;
15 | import com.softbankrobotics.sample.returntomapframe.core.MapManager;
16 | import com.softbankrobotics.sample.returntomapframe.utils.FutureCancellations;
17 |
18 | import java.util.concurrent.atomic.AtomicBoolean;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 |
23 | /**
24 | * Manager that starts the localization.
25 | */
26 | public class LocalizeManager {
27 |
28 | @NonNull
29 | private static final String TAG = "LocalizeManager";
30 |
31 | @NonNull
32 | private final AtomicBoolean isLocalized = new AtomicBoolean(false);
33 |
34 | @Nullable
35 | private Localize localize;
36 | @Nullable
37 | private Future localization;
38 |
39 | /**
40 | * Indicate if the robot is localized or not.
41 | *
42 | * @return {@code true} if the robot is localized, {@code false} otherwise.
43 | */
44 | public boolean isLocalized() {
45 | return isLocalized.get();
46 | }
47 |
48 | /**
49 | * Indicates if the map is loaded.
50 | *
51 | * @return {@code true} if the map is loaded, {@code false} otherwise.
52 | */
53 | public boolean mapIsLoaded() {
54 | return localize != null;
55 | }
56 |
57 | /**
58 | * Load the map and create the {@link Localize} action.
59 | *
60 | * @param qiContext the qiContext
61 | * @return A {@link Future} wrapping the operation.
62 | */
63 | @NonNull
64 | public Future loadMap(@NonNull QiContext qiContext) {
65 | return MapManager.retrieveMap(qiContext)
66 | .andThenCompose(map -> {
67 | Log.d(TAG, "Map retrieved successfully");
68 | Log.d(TAG, "Building Localize...");
69 | return LocalizeBuilder.with(qiContext)
70 | .withMap(map)
71 | .buildAsync();
72 | })
73 | .andThenConsume(loc -> {
74 | Log.d(TAG, "Localize built successfully");
75 | localize = loc;
76 | });
77 | }
78 |
79 | /**
80 | * Localize the robot. This method starts the localization and waits for the robot to be localized.
81 | * Once localized, the operation is considered as successful and the robot stays localized until the localization is cancelled or encounters an error.
82 | *
83 | * @return A {@link Future} wrapping the operation.
84 | * This operation is a success when the robot is localized.
85 | * If the {@link Localize} action is cancelled before that, the operation is cancelled.
86 | * If the {@link Localize} action encounters an error before that, the operation fails.
87 | */
88 | @NonNull
89 | public Future localizeRobot() {
90 | // Promise used to set the operation result.
91 | Promise promise = new Promise<>();
92 |
93 | // Cancel the running localization if any, and start a new localization.
94 | FutureCancellations.cancel(localization)
95 | .andThenCompose(ignored -> {
96 | if (localize == null) {
97 | throw new IllegalStateException("localize is null");
98 | }
99 |
100 | localize.addOnStatusChangedListener(status -> {
101 | if (status == LocalizationStatus.LOCALIZED) {
102 | Log.d(TAG, "Robot is localized");
103 | isLocalized.set(true);
104 | if (!promise.getFuture().isDone()) {
105 | // Once the robot is localized, consider the operation as a success.
106 | promise.setValue(null);
107 | }
108 | }
109 | });
110 |
111 | Log.d(TAG, "Running Localize...");
112 | localization = localize.async().run();
113 | return localization;
114 | })
115 | .thenConsume(future -> {
116 | isLocalized.set(false);
117 |
118 | if (localize != null) {
119 | localize.removeAllOnStatusChangedListeners();
120 | }
121 |
122 | if (future.hasError()) {
123 | Log.e(TAG, "Error while localizing", future.getError());
124 | if (!promise.getFuture().isDone()) {
125 | // Consider the operation as a failure.
126 | promise.setError(future.getErrorMessage());
127 | }
128 | } else if (future.isCancelled()) {
129 | if (!promise.getFuture().isDone()) {
130 | // Consider the operation has been cancelled.
131 | promise.setCancelled();
132 | }
133 | }
134 | });
135 |
136 | // Return the future associated with the promise.
137 | return promise.getFuture();
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/LocalizationActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization;
6 |
7 | import android.os.Bundle;
8 | import android.util.Log;
9 | import android.widget.TextView;
10 |
11 | import com.aldebaran.qi.sdk.QiContext;
12 | import com.aldebaran.qi.sdk.QiSDK;
13 | import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
14 | import com.aldebaran.qi.sdk.design.activity.RobotActivity;
15 | import com.softbankrobotics.sample.returntomapframe.R;
16 | import com.softbankrobotics.sample.returntomapframe.localization.gotoorigin.GoToOriginScreen;
17 | import com.softbankrobotics.sample.returntomapframe.localization.localizationmenu.LocalizationMenuScreen;
18 | import com.softbankrobotics.sample.returntomapframe.localization.localize.LocalizeScreen;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import androidx.annotation.StringRes;
23 | import androidx.fragment.app.Fragment;
24 | import butterknife.BindView;
25 | import butterknife.ButterKnife;
26 | import butterknife.OnClick;
27 | import io.reactivex.disposables.Disposable;
28 | import io.reactivex.schedulers.Schedulers;
29 |
30 | /**
31 | * The localization Activity.
32 | */
33 | public class LocalizationActivity extends RobotActivity implements RobotLifecycleCallbacks {
34 |
35 | @NonNull
36 | private static final String TAG = "LocalizationActivity";
37 |
38 | @NonNull
39 | private final ScreenMachine screenMachine = new ScreenMachine();
40 |
41 | @NonNull
42 | private final LocalizeManager localizeManager = new LocalizeManager();
43 |
44 | @Nullable
45 | private QiContext qiContext;
46 |
47 | @Nullable
48 | private Screen currentScreen;
49 |
50 | @Nullable
51 | private Disposable disposable;
52 |
53 | @BindView(R.id.titleTextView)
54 | TextView titleTextView;
55 |
56 | @Override
57 | protected void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 |
60 | setContentView(R.layout.activity_localization);
61 | ButterKnife.bind(this);
62 |
63 | QiSDK.register(this, this);
64 | }
65 |
66 | @Override
67 | protected void onResume() {
68 | super.onResume();
69 |
70 | disposable = screenMachine.screenState()
71 | .subscribeOn(Schedulers.io())
72 | .observeOn(Schedulers.io())
73 | .subscribe(this::onScreenStateChanged);
74 | }
75 |
76 | @Override
77 | protected void onPause() {
78 | if (disposable != null && !disposable.isDisposed()) {
79 | disposable.dispose();
80 | }
81 |
82 | super.onPause();
83 | }
84 |
85 | @Override
86 | protected void onDestroy() {
87 | QiSDK.unregister(this, this);
88 | super.onDestroy();
89 | }
90 |
91 | @Override
92 | public void onBackPressed() {
93 | screenMachine.post(ScreenEvent.BACK);
94 | }
95 |
96 | @Override
97 | public void onRobotFocusGained(QiContext qiContext) {
98 | this.qiContext = qiContext;
99 | screenMachine.post(ScreenEvent.FOCUS_GAINED);
100 | }
101 |
102 | @Override
103 | public void onRobotFocusLost() {
104 | this.qiContext = null;
105 | screenMachine.post(ScreenEvent.FOCUS_LOST);
106 | }
107 |
108 | @Override
109 | public void onRobotFocusRefused(String reason) {
110 | Log.e(TAG, "onRobotFocusRefused: " + reason);
111 | }
112 |
113 | @OnClick(R.id.closeButton)
114 | public void onCloseClicked() {
115 | finishAffinity();
116 | }
117 |
118 | @OnClick(R.id.backButton)
119 | public void onBackClicked() {
120 | onBackPressed();
121 | }
122 |
123 | /**
124 | * Show the specified fragment.
125 | *
126 | * @param fragment the fragment to show
127 | */
128 | public void showFragment(@NonNull Fragment fragment) {
129 | runOnUiThread(() ->
130 | getSupportFragmentManager()
131 | .beginTransaction()
132 | .replace(R.id.container, fragment)
133 | .commit());
134 | }
135 |
136 | /**
137 | * Provide the {@link ScreenMachine}.
138 | *
139 | * @return The {@link ScreenMachine}.
140 | */
141 | @NonNull
142 | public ScreenMachine getScreenMachine() {
143 | return screenMachine;
144 | }
145 |
146 | /**
147 | * Set the title in the navigation bar.
148 | *
149 | * @param titleRes the string resource for the title
150 | */
151 | public void setNavigationTitle(@StringRes int titleRes) {
152 | runOnUiThread(() -> titleTextView.setText(titleRes));
153 | }
154 |
155 | private void startLocalizationMenuScreen() {
156 | startScreen(new LocalizationMenuScreen(this, localizeManager));
157 | }
158 |
159 | private void startLocalizeScreen() {
160 | startScreen(new LocalizeScreen(this, localizeManager));
161 | }
162 |
163 | private void startGoToOriginScreen() {
164 | startScreen(new GoToOriginScreen(this));
165 | }
166 |
167 | private void startScreen(@NonNull Screen screen) {
168 | if (currentScreen == null) {
169 | doStartScreen(screen);
170 | return;
171 | }
172 |
173 | currentScreen.stop().andThenConsume(ignored -> doStartScreen(screen));
174 | }
175 |
176 | private void doStartScreen(@NonNull Screen screen) {
177 | if (qiContext != null) {
178 | currentScreen = screen;
179 | screen.start(qiContext);
180 | }
181 | }
182 |
183 | private void onScreenStateChanged(@NonNull ScreenState screenState) {
184 | Log.d(TAG, "onScreenStateChanged: " + screenState);
185 |
186 | switch (screenState) {
187 | case NONE:
188 | if (currentScreen != null) {
189 | currentScreen.stop();
190 | currentScreen = null;
191 | }
192 | break;
193 | case LOCALIZATION_MENU:
194 | startLocalizationMenuScreen();
195 | break;
196 | case LOCALIZE:
197 | startLocalizeScreen();
198 | break;
199 | case GO_TO_ORIGIN:
200 | startGoToOriginScreen();
201 | break;
202 | case END:
203 | runOnUiThread(this::finish);
204 | break;
205 | }
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/gotoorigin/GoToOriginFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.gotoorigin;
6 |
7 | import android.media.MediaPlayer;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.Button;
14 | import android.widget.ImageView;
15 | import android.widget.TextView;
16 |
17 | import com.airbnb.lottie.LottieAnimationView;
18 | import com.softbankrobotics.sample.returntomapframe.R;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import androidx.annotation.RawRes;
23 | import androidx.fragment.app.Fragment;
24 | import androidx.fragment.app.FragmentActivity;
25 | import butterknife.BindView;
26 | import butterknife.ButterKnife;
27 | import butterknife.OnClick;
28 | import butterknife.Unbinder;
29 | import io.reactivex.android.schedulers.AndroidSchedulers;
30 | import io.reactivex.disposables.Disposable;
31 | import io.reactivex.schedulers.Schedulers;
32 |
33 | /**
34 | * The go to origin Fragment.
35 | */
36 | public class GoToOriginFragment extends Fragment {
37 |
38 | @NonNull
39 | private static final String TAG = "GoToOriginFragment";
40 |
41 | @Nullable
42 | private GoToOriginScreen screen;
43 | @Nullable
44 | private GoToOriginMachine machine;
45 |
46 | @Nullable
47 | private Unbinder unbinder;
48 |
49 | @BindView(R.id.startGoToButton)
50 | Button startGoToButton;
51 |
52 | @BindView(R.id.infoTextView)
53 | TextView infoTextView;
54 |
55 | @BindView(R.id.warningImage)
56 | ImageView warningImage;
57 |
58 | @BindView(R.id.successImage)
59 | ImageView successImage;
60 |
61 | @BindView(R.id.progressAnimationView)
62 | LottieAnimationView progressAnimationView;
63 |
64 | @Nullable
65 | private Disposable disposable;
66 |
67 | @Nullable
68 | private MediaPlayer mediaPlayer;
69 |
70 | @Override
71 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
72 | Bundle savedInstanceState) {
73 | View view = inflater.inflate(R.layout.fragment_go_to_origin, container, false);
74 | unbinder = ButterKnife.bind(this, view);
75 | return view;
76 | }
77 |
78 | @Override
79 | public void onResume() {
80 | super.onResume();
81 |
82 | infoTextView.setVisibility(View.INVISIBLE);
83 | startGoToButton.setVisibility(View.INVISIBLE);
84 | warningImage.setVisibility(View.INVISIBLE);
85 | successImage.setVisibility(View.INVISIBLE);
86 | progressAnimationView.setVisibility(View.INVISIBLE);
87 |
88 | if (machine != null) {
89 | disposable = machine.goToOriginState()
90 | .subscribeOn(Schedulers.io())
91 | .observeOn(AndroidSchedulers.mainThread())
92 | .subscribe(this::onGoToOriginStateChanged);
93 | }
94 | }
95 |
96 | @Override
97 | public void onPause() {
98 | if (disposable != null && !disposable.isDisposed()) {
99 | disposable.dispose();
100 | }
101 |
102 | if (mediaPlayer != null) {
103 | mediaPlayer.release();
104 | mediaPlayer = null;
105 | }
106 |
107 | super.onPause();
108 | }
109 |
110 | @Override
111 | public void onDestroyView() {
112 | if (unbinder != null) {
113 | unbinder.unbind();
114 | }
115 | super.onDestroyView();
116 | }
117 |
118 | @OnClick(R.id.startGoToButton)
119 | public void onClickStartGoTo() {
120 | if (machine != null) {
121 | machine.post(GoToOriginEvent.START_GO_TO_ORIGIN);
122 | }
123 | }
124 |
125 | @NonNull
126 | static GoToOriginFragment newInstance(@NonNull GoToOriginScreen screen, @NonNull GoToOriginMachine machine) {
127 | GoToOriginFragment fragment = new GoToOriginFragment();
128 | fragment.screen = screen;
129 | fragment.machine = machine;
130 | return fragment;
131 | }
132 |
133 | private void playSound(@RawRes int soundResId) {
134 | if (mediaPlayer != null) {
135 | mediaPlayer.release();
136 | }
137 |
138 | FragmentActivity activity = getActivity();
139 | if (activity != null) {
140 | mediaPlayer = MediaPlayer.create(activity, soundResId);
141 | mediaPlayer.start();
142 | }
143 | }
144 |
145 | private void onGoToOriginStateChanged(@NonNull GoToOriginState goToOriginState) {
146 | Log.d(TAG, "onGoToOriginStateChanged: " + goToOriginState);
147 |
148 | switch (goToOriginState) {
149 | case IDLE:
150 | infoTextView.setVisibility(View.INVISIBLE);
151 | startGoToButton.setVisibility(View.INVISIBLE);
152 | warningImage.setVisibility(View.GONE);
153 | successImage.setVisibility(View.INVISIBLE);
154 | progressAnimationView.setVisibility(View.INVISIBLE);
155 | break;
156 | case BRIEFING:
157 | infoTextView.setVisibility(View.VISIBLE);
158 | startGoToButton.setVisibility(View.VISIBLE);
159 | warningImage.setVisibility(View.GONE);
160 | successImage.setVisibility(View.INVISIBLE);
161 | infoTextView.setText(R.string.go_to_origin_briefing_text);
162 | progressAnimationView.setVisibility(View.INVISIBLE);
163 | break;
164 | case MOVING:
165 | infoTextView.setVisibility(View.VISIBLE);
166 | startGoToButton.setVisibility(View.INVISIBLE);
167 | warningImage.setVisibility(View.GONE);
168 | successImage.setVisibility(View.INVISIBLE);
169 | infoTextView.setText(R.string.go_to_origin_moving_text);
170 | progressAnimationView.setVisibility(View.VISIBLE);
171 | break;
172 | case ERROR:
173 | infoTextView.setVisibility(View.VISIBLE);
174 | startGoToButton.setVisibility(View.VISIBLE);
175 | warningImage.setVisibility(View.VISIBLE);
176 | successImage.setVisibility(View.INVISIBLE);
177 | infoTextView.setText(R.string.error_text);
178 | progressAnimationView.setVisibility(View.INVISIBLE);
179 | playSound(R.raw.error);
180 | break;
181 | case SUCCESS:
182 | infoTextView.setVisibility(View.VISIBLE);
183 | startGoToButton.setVisibility(View.INVISIBLE);
184 | warningImage.setVisibility(View.GONE);
185 | successImage.setVisibility(View.VISIBLE);
186 | infoTextView.setText(R.string.success_text);
187 | progressAnimationView.setVisibility(View.INVISIBLE);
188 | playSound(R.raw.success);
189 | break;
190 | case END:
191 | if (screen != null) {
192 | screen.onGoToOriginEnd();
193 | }
194 | break;
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/mapping/MappingActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.mapping;
6 |
7 | import android.media.MediaPlayer;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.View;
11 | import android.widget.Button;
12 | import android.widget.ImageView;
13 | import android.widget.TextView;
14 |
15 | import com.airbnb.lottie.LottieAnimationView;
16 | import com.aldebaran.qi.sdk.QiSDK;
17 | import com.aldebaran.qi.sdk.design.activity.RobotActivity;
18 | import com.softbankrobotics.sample.returntomapframe.R;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import androidx.annotation.RawRes;
23 | import butterknife.BindView;
24 | import butterknife.ButterKnife;
25 | import butterknife.OnClick;
26 | import io.reactivex.android.schedulers.AndroidSchedulers;
27 | import io.reactivex.disposables.Disposable;
28 | import io.reactivex.schedulers.Schedulers;
29 |
30 | /**
31 | * The mapping Activity.
32 | */
33 | public class MappingActivity extends RobotActivity {
34 |
35 | @NonNull
36 | private static final String TAG = "MappingActivity";
37 |
38 | @NonNull
39 | private final MappingMachine machine = new MappingMachine();
40 |
41 | @NonNull
42 | private final MappingRobot robot = new MappingRobot(machine);
43 |
44 | @BindView(R.id.startMappingButton)
45 | Button startMappingButton;
46 |
47 | @BindView(R.id.infoTextView)
48 | TextView infoTextView;
49 |
50 | @BindView(R.id.warningImage)
51 | ImageView warningImage;
52 |
53 | @BindView(R.id.infoImageView)
54 | ImageView infoImageView;
55 |
56 | @BindView(R.id.progressAnimationView)
57 | LottieAnimationView progressAnimationView;
58 |
59 | @Nullable
60 | private Disposable disposable;
61 |
62 | @Nullable
63 | private MediaPlayer mediaPlayer;
64 |
65 | @Override
66 | protected void onCreate(Bundle savedInstanceState) {
67 | super.onCreate(savedInstanceState);
68 |
69 | setContentView(R.layout.activity_mapping);
70 | ButterKnife.bind(this);
71 |
72 | QiSDK.register(this, robot);
73 | }
74 |
75 | @Override
76 | protected void onResume() {
77 | super.onResume();
78 |
79 | infoTextView.setVisibility(View.INVISIBLE);
80 | startMappingButton.setVisibility(View.INVISIBLE);
81 | warningImage.setVisibility(View.INVISIBLE);
82 | infoImageView.setVisibility(View.INVISIBLE);
83 | progressAnimationView.setVisibility(View.INVISIBLE);
84 |
85 | disposable = machine.mappingState()
86 | .subscribeOn(Schedulers.io())
87 | .observeOn(AndroidSchedulers.mainThread())
88 | .subscribe(this::onMappingStateChanged);
89 | }
90 |
91 | @Override
92 | protected void onPause() {
93 | if (disposable != null && !disposable.isDisposed()) {
94 | disposable.dispose();
95 | }
96 |
97 | if (mediaPlayer != null) {
98 | mediaPlayer.release();
99 | mediaPlayer = null;
100 | }
101 |
102 | super.onPause();
103 | }
104 |
105 | @Override
106 | protected void onDestroy() {
107 | QiSDK.unregister(this, robot);
108 | super.onDestroy();
109 | }
110 |
111 | @OnClick(R.id.startMappingButton)
112 | public void onClickStartMapping() {
113 | machine.post(MappingEvent.START_MAPPING);
114 | }
115 |
116 | @OnClick(R.id.closeButton)
117 | public void onCloseClicked() {
118 | finishAffinity();
119 | }
120 |
121 | @OnClick(R.id.backButton)
122 | public void onBackClicked() {
123 | onBackPressed();
124 | }
125 |
126 | private void playSound(@RawRes int soundResId, boolean playInLoop) {
127 | if (mediaPlayer != null) {
128 | mediaPlayer.release();
129 | }
130 | mediaPlayer = MediaPlayer.create(this, soundResId);
131 | mediaPlayer.setLooping(playInLoop);
132 | mediaPlayer.start();
133 | }
134 |
135 | private void onMappingStateChanged(@NonNull MappingState mappingState) {
136 | Log.d(TAG, "onMappingStateChanged: " + mappingState);
137 |
138 | switch (mappingState) {
139 | case IDLE:
140 | infoTextView.setVisibility(View.INVISIBLE);
141 | startMappingButton.setVisibility(View.INVISIBLE);
142 | warningImage.setVisibility(View.GONE);
143 | infoImageView.setVisibility(View.INVISIBLE);
144 | progressAnimationView.setVisibility(View.INVISIBLE);
145 | break;
146 | case BRIEFING:
147 | infoTextView.setVisibility(View.VISIBLE);
148 | startMappingButton.setVisibility(View.VISIBLE);
149 | warningImage.setVisibility(View.GONE);
150 | infoImageView.setVisibility(View.INVISIBLE);
151 | progressAnimationView.setVisibility(View.INVISIBLE);
152 | infoTextView.setText(R.string.briefing_text);
153 | break;
154 | case ADVICES:
155 | infoTextView.setVisibility(View.VISIBLE);
156 | startMappingButton.setVisibility(View.INVISIBLE);
157 | warningImage.setVisibility(View.GONE);
158 | infoImageView.setVisibility(View.VISIBLE);
159 | progressAnimationView.setVisibility(View.INVISIBLE);
160 | infoTextView.setText(R.string.advices_text);
161 | infoImageView.setImageResource(R.drawable.hiding);
162 | break;
163 | case MAPPING:
164 | infoTextView.setVisibility(View.VISIBLE);
165 | startMappingButton.setVisibility(View.INVISIBLE);
166 | warningImage.setVisibility(View.GONE);
167 | infoImageView.setVisibility(View.INVISIBLE);
168 | progressAnimationView.setVisibility(View.VISIBLE);
169 | infoTextView.setText(R.string.mapping_mapping_text);
170 | playSound(R.raw.sonar, true);
171 | break;
172 | case SAVING_MAP:
173 | infoTextView.setVisibility(View.VISIBLE);
174 | startMappingButton.setVisibility(View.INVISIBLE);
175 | warningImage.setVisibility(View.GONE);
176 | infoImageView.setVisibility(View.INVISIBLE);
177 | progressAnimationView.setVisibility(View.VISIBLE);
178 | infoTextView.setText(R.string.mapping_saving_map_text);
179 | playSound(R.raw.processing, true);
180 | break;
181 | case ERROR:
182 | infoTextView.setVisibility(View.VISIBLE);
183 | startMappingButton.setVisibility(View.VISIBLE);
184 | warningImage.setVisibility(View.VISIBLE);
185 | infoImageView.setVisibility(View.INVISIBLE);
186 | progressAnimationView.setVisibility(View.INVISIBLE);
187 | infoTextView.setText(R.string.error_text);
188 | playSound(R.raw.error, false);
189 | break;
190 | case SUCCESS:
191 | infoTextView.setVisibility(View.VISIBLE);
192 | startMappingButton.setVisibility(View.INVISIBLE);
193 | warningImage.setVisibility(View.GONE);
194 | infoImageView.setVisibility(View.VISIBLE);
195 | progressAnimationView.setVisibility(View.INVISIBLE);
196 | infoTextView.setText(R.string.success_text);
197 | infoImageView.setImageResource(R.drawable.ic_check);
198 | playSound(R.raw.success, false);
199 | break;
200 | case END:
201 | finish();
202 | break;
203 | }
204 | }
205 | }
206 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/mapping/MappingRobot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.mapping;
6 |
7 | import android.util.Log;
8 |
9 | import com.aldebaran.qi.Future;
10 | import com.aldebaran.qi.sdk.QiContext;
11 | import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
12 | import com.aldebaran.qi.sdk.builder.LocalizeAndMapBuilder;
13 | import com.aldebaran.qi.sdk.builder.SayBuilder;
14 | import com.aldebaran.qi.sdk.object.actuation.LocalizationStatus;
15 | import com.aldebaran.qi.sdk.object.actuation.LocalizeAndMap;
16 | import com.softbankrobotics.sample.returntomapframe.R;
17 | import com.softbankrobotics.sample.returntomapframe.core.MapManager;
18 | import com.softbankrobotics.sample.returntomapframe.utils.FutureCancellations;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import androidx.annotation.StringRes;
23 | import io.reactivex.disposables.Disposable;
24 | import io.reactivex.schedulers.Schedulers;
25 |
26 | /**
27 | * The robot for {@link MappingActivity}.
28 | */
29 | class MappingRobot implements RobotLifecycleCallbacks {
30 |
31 | @NonNull
32 | private static final String TAG = "MappingRobot";
33 |
34 | @NonNull
35 | private final MappingMachine machine;
36 |
37 | @Nullable
38 | private Disposable disposable;
39 |
40 | @Nullable
41 | private QiContext qiContext;
42 | @Nullable
43 | private LocalizeAndMap localizeAndMap;
44 | @Nullable
45 | private Future mapping;
46 | @Nullable
47 | private Future speech;
48 |
49 | MappingRobot(@NonNull MappingMachine machine) {
50 | this.machine = machine;
51 | }
52 |
53 | @Override
54 | public void onRobotFocusGained(QiContext qiContext) {
55 | this.qiContext = qiContext;
56 |
57 | machine.post(MappingEvent.FOCUS_GAINED);
58 |
59 | disposable = machine.mappingState()
60 | .subscribeOn(Schedulers.io())
61 | .observeOn(Schedulers.io())
62 | .subscribe(this::onMappingStateChanged);
63 | }
64 |
65 | @Override
66 | public void onRobotFocusLost() {
67 | machine.post(MappingEvent.FOCUS_LOST);
68 |
69 | if (disposable != null && !disposable.isDisposed()) {
70 | disposable.dispose();
71 | }
72 |
73 | this.qiContext = null;
74 | }
75 |
76 | @Override
77 | public void onRobotFocusRefused(String reason) {
78 | Log.e(TAG, "onRobotFocusRefused: " + reason);
79 | }
80 |
81 | private void startMapping() {
82 | if (qiContext == null) {
83 | Log.e(TAG, "Error while mapping: qiContext is null");
84 | machine.post(MappingEvent.MAPPING_FAILED);
85 | return;
86 | }
87 |
88 | // Create the LocalizeAndMap and run it.
89 | mapping = LocalizeAndMapBuilder.with(qiContext).buildAsync()
90 | .andThenCompose(loc -> {
91 | localizeAndMap = loc;
92 |
93 | localizeAndMap.addOnStatusChangedListener(status -> {
94 | // Once localized, stop the mapping.
95 | if (status == LocalizationStatus.LOCALIZED) {
96 | stopMapping();
97 | machine.post(MappingEvent.MAPPING_SUCCEEDED);
98 | }
99 | });
100 |
101 | return localizeAndMap.async().run();
102 | })
103 | .thenConsume(future -> {
104 | if (localizeAndMap != null) {
105 | localizeAndMap.removeAllOnStatusChangedListeners();
106 | }
107 |
108 | if (future.hasError()) {
109 | Log.e(TAG, "Error while mapping", future.getError());
110 | machine.post(MappingEvent.MAPPING_FAILED);
111 | }
112 | });
113 | }
114 |
115 | private void stopMapping() {
116 | if (mapping != null) {
117 | mapping.cancel(true);
118 | }
119 | }
120 |
121 | private void saveMap() {
122 | if (localizeAndMap == null) {
123 | Log.e(TAG, "Error while saving map: localizeAndMap is null");
124 | machine.post(MappingEvent.SAVING_MAP_FAILED);
125 | return;
126 | }
127 |
128 | // Dump the map and save it.
129 | localizeAndMap.async().dumpMap()
130 | .andThenCompose(map -> {
131 | if (qiContext == null) {
132 | throw new IllegalStateException("qiContext is null");
133 | }
134 |
135 | Log.d(TAG, "Saving map...");
136 | return MapManager.saveMap(qiContext, map);
137 | })
138 | .thenConsume(future -> {
139 | if (future.isSuccess()) {
140 | Log.d(TAG, "Map saved successfully");
141 | machine.post(MappingEvent.SAVING_MAP_SUCCEEDED);
142 | } else if (future.hasError()) {
143 | Log.e(TAG, "Error while saving map", future.getError());
144 | machine.post(MappingEvent.SAVING_MAP_FAILED);
145 | }
146 | });
147 | }
148 |
149 | @NonNull
150 | private Future say(@StringRes int resId) {
151 | return FutureCancellations.cancel(speech)
152 | .andThenCompose(ignored -> {
153 | if (qiContext == null) {
154 | throw new IllegalStateException("qiContext is null");
155 | }
156 |
157 | Future newSpeech = SayBuilder.with(qiContext)
158 | .withText(qiContext.getString(resId))
159 | .buildAsync()
160 | .andThenCompose(say -> say.async().run());
161 |
162 | speech = newSpeech;
163 | return newSpeech;
164 | });
165 | }
166 |
167 | @NonNull
168 | private Future cancelCurrentActions() {
169 | return FutureCancellations.cancel(speech, mapping);
170 | }
171 |
172 | private void onMappingStateChanged(@NonNull MappingState mappingState) {
173 | Log.d(TAG, "onMappingStateChanged: " + mappingState);
174 |
175 | switch (mappingState) {
176 | case IDLE:
177 | case END:
178 | cancelCurrentActions();
179 | break;
180 | case BRIEFING:
181 | cancelCurrentActions()
182 | .andThenCompose(ignored -> say(R.string.briefing_speech));
183 | break;
184 | case ADVICES:
185 | cancelCurrentActions()
186 | .andThenCompose(ignored -> say(R.string.mapping_advices_speech))
187 | .andThenCompose(ignored -> say(R.string.countdown_speech))
188 | .andThenConsume(ignored -> machine.post(MappingEvent.ADVICES_ENDED));
189 | break;
190 | case MAPPING:
191 | cancelCurrentActions()
192 | .andThenConsume(ignored -> startMapping());
193 | break;
194 | case SAVING_MAP:
195 | cancelCurrentActions()
196 | .andThenCompose(ignored -> say(R.string.mapping_saving_map_speech))
197 | .andThenConsume(ignored -> saveMap());
198 | break;
199 | case ERROR:
200 | cancelCurrentActions()
201 | .andThenCompose(ignored -> say(R.string.error_speech));
202 | break;
203 | case SUCCESS:
204 | cancelCurrentActions()
205 | .andThenCompose(ignored -> say(R.string.mapping_success_speech))
206 | .andThenConsume(ignored -> machine.post(MappingEvent.SUCCESS_CONFIRMED));
207 | break;
208 | }
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localizationmenu/LocalizationMenuRobot.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localizationmenu;
6 |
7 | import com.aldebaran.qi.Future;
8 | import com.aldebaran.qi.sdk.QiContext;
9 | import com.aldebaran.qi.sdk.builder.ChatBuilder;
10 | import com.aldebaran.qi.sdk.builder.QiChatbotBuilder;
11 | import com.aldebaran.qi.sdk.builder.TopicBuilder;
12 | import com.aldebaran.qi.sdk.object.conversation.AutonomousReactionImportance;
13 | import com.aldebaran.qi.sdk.object.conversation.AutonomousReactionValidity;
14 | import com.aldebaran.qi.sdk.object.conversation.Bookmark;
15 | import com.aldebaran.qi.sdk.object.conversation.BookmarkStatus;
16 | import com.aldebaran.qi.sdk.object.conversation.Chat;
17 | import com.aldebaran.qi.sdk.object.conversation.QiChatVariable;
18 | import com.aldebaran.qi.sdk.object.conversation.QiChatbot;
19 | import com.aldebaran.qi.sdk.object.conversation.Topic;
20 | import com.softbankrobotics.sample.returntomapframe.R;
21 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizeManager;
22 | import com.softbankrobotics.sample.returntomapframe.localization.Robot;
23 | import com.softbankrobotics.sample.returntomapframe.utils.FutureCancellations;
24 |
25 | import java.util.Map;
26 | import java.util.concurrent.TimeUnit;
27 | import java.util.concurrent.atomic.AtomicBoolean;
28 |
29 | import androidx.annotation.NonNull;
30 | import androidx.annotation.Nullable;
31 | import io.reactivex.Single;
32 | import io.reactivex.disposables.Disposable;
33 | import io.reactivex.schedulers.Schedulers;
34 |
35 | /**
36 | * The robot for {@link LocalizationMenuScreen}.
37 | */
38 | class LocalizationMenuRobot implements Robot {
39 |
40 | @NonNull
41 | private static final String START_BOOKMARK_NAME = "start";
42 | @NonNull
43 | private static final String LOCALIZE_BOOKMARK_NAME = "localize";
44 | @NonNull
45 | private static final String LOCALIZE_END_BOOKMARK_NAME = "localize_end";
46 | @NonNull
47 | private static final String GO_TO_ORIGIN_BOOKMARK_NAME = "go_to_origin";
48 | @NonNull
49 | private static final String GO_TO_ORIGIN_END_BOOKMARK_NAME = "go_to_origin_end";
50 | @NonNull
51 | private static final String LOCALIZED_BOOKMARK_NAME = "localized";
52 | @NonNull
53 | private static final String START_TIMER_BOOKMARK_NAME = "start_timer";
54 | @NonNull
55 | private static final String STOP_TIMER_BOOKMARK_NAME = "stop_timer";
56 |
57 | @NonNull
58 | private final LocalizationMenuScreen screen;
59 | @NonNull
60 | private final LocalizeManager localizeManager;
61 |
62 | @Nullable
63 | private Disposable timerDisposable;
64 | @NonNull
65 | private final AtomicBoolean shouldRepeatWithTimer = new AtomicBoolean(true);
66 |
67 | @Nullable
68 | private Map bookmarks;
69 | @Nullable
70 | private QiChatbot qiChatbot;
71 | @Nullable
72 | private Chat chat;
73 | @Nullable
74 | private Future discussion;
75 |
76 | LocalizationMenuRobot(@NonNull LocalizationMenuScreen screen, @NonNull LocalizeManager localizeManager) {
77 | this.screen = screen;
78 | this.localizeManager = localizeManager;
79 | }
80 |
81 | @NonNull
82 | @Override
83 | public Future stop() {
84 | stopTimer();
85 |
86 | bookmarks = null;
87 | if (qiChatbot != null) {
88 | qiChatbot.removeAllOnBookmarkReachedListeners();
89 | qiChatbot = null;
90 | }
91 | if (chat != null) {
92 | chat.removeAllOnStartedListeners();
93 | chat = null;
94 | }
95 | return FutureCancellations.cancel(discussion);
96 | }
97 |
98 | void startDiscussion(@NonNull QiContext qiContext) {
99 | shouldRepeatWithTimer.set(true);
100 |
101 | Topic topic = TopicBuilder.with(qiContext)
102 | .withResource(R.raw.localization_menu)
103 | .build();
104 |
105 | bookmarks = topic.getBookmarks();
106 |
107 | qiChatbot = QiChatbotBuilder.with(qiContext)
108 | .withTopic(topic)
109 | .build();
110 |
111 | if (qiChatbot != null) {
112 | QiChatVariable proposalVariable = qiChatbot.variable("proposal");
113 |
114 | // Change the speech and enable/disable the "go to origin" option, depending on the localization status.
115 | if (localizeManager.isLocalized()) {
116 | proposalVariable.setValue(qiContext.getString(R.string.localization_menu_sentence_localized));
117 | screen.enableGoToOrigin();
118 | } else if (bookmarks != null) {
119 | proposalVariable.setValue(qiContext.getString(R.string.localization_menu_sentence_not_localized));
120 | BookmarkStatus bookmarkStatus = qiChatbot.bookmarkStatus(bookmarks.get(LOCALIZED_BOOKMARK_NAME));
121 | bookmarkStatus.setEnabled(false);
122 | }
123 |
124 | qiChatbot.addOnBookmarkReachedListener(bookmark -> {
125 | switch (bookmark.getName()) {
126 | case LOCALIZE_BOOKMARK_NAME:
127 | screen.selectLocalize();
128 | screen.disableChoices();
129 | break;
130 | case LOCALIZED_BOOKMARK_NAME:
131 | screen.selectGoToOrigin();
132 | screen.disableChoices();
133 | break;
134 | case LOCALIZE_END_BOOKMARK_NAME:
135 | screen.onLocalizeSelected();
136 | break;
137 | case GO_TO_ORIGIN_END_BOOKMARK_NAME:
138 | screen.onGoToOriginSelected();
139 | break;
140 | case START_TIMER_BOOKMARK_NAME:
141 | if (shouldRepeatWithTimer.getAndSet(false)) {
142 | startTimer();
143 | }
144 | break;
145 | case STOP_TIMER_BOOKMARK_NAME:
146 | stopTimer();
147 | break;
148 | }
149 | });
150 | }
151 |
152 | chat = ChatBuilder.with(qiContext)
153 | .withChatbot(qiChatbot)
154 | .build();
155 |
156 | chat.addOnStartedListener(() -> goToBookmark(START_BOOKMARK_NAME, AutonomousReactionImportance.LOW));
157 |
158 | discussion = chat.async().run();
159 | }
160 |
161 | void goToLocalizeBookmark() {
162 | if (!goToBookmark(LOCALIZE_BOOKMARK_NAME, AutonomousReactionImportance.HIGH)) {
163 | screen.onLocalizeSelected();
164 | }
165 | }
166 |
167 | void goToGoToInitialPositionBookmark() {
168 | if (!goToBookmark(GO_TO_ORIGIN_BOOKMARK_NAME, AutonomousReactionImportance.HIGH)) {
169 | screen.onGoToOriginSelected();
170 | }
171 | }
172 |
173 | private boolean goToBookmark(@NonNull String name, @NonNull AutonomousReactionImportance importance) {
174 | Bookmark bookmark;
175 | if ((bookmarks == null)
176 | || ((bookmark = bookmarks.get(name)) == null)
177 | || (qiChatbot == null)) {
178 | return false;
179 | }
180 |
181 | qiChatbot.async().goToBookmark(bookmark, importance, AutonomousReactionValidity.IMMEDIATE);
182 | return true;
183 | }
184 |
185 | private void startTimer() {
186 | timerDisposable = Single.timer(5, TimeUnit.SECONDS)
187 | .observeOn(Schedulers.io())
188 | .subscribeOn(Schedulers.io())
189 | .subscribe(ignored -> {
190 | stopTimer();
191 | goToBookmark(START_BOOKMARK_NAME, AutonomousReactionImportance.LOW);
192 | });
193 | }
194 |
195 | private void stopTimer() {
196 | if (timerDisposable != null && !timerDisposable.isDisposed()) {
197 | timerDisposable.dispose();
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/localization/localize/LocalizeFragment.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 SoftBank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.localization.localize;
6 |
7 | import android.media.MediaPlayer;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.view.LayoutInflater;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.Button;
14 | import android.widget.ImageView;
15 | import android.widget.TextView;
16 |
17 | import com.airbnb.lottie.LottieAnimationView;
18 | import com.softbankrobotics.sample.returntomapframe.R;
19 |
20 | import androidx.annotation.NonNull;
21 | import androidx.annotation.Nullable;
22 | import androidx.annotation.RawRes;
23 | import androidx.fragment.app.Fragment;
24 | import androidx.fragment.app.FragmentActivity;
25 | import butterknife.BindView;
26 | import butterknife.ButterKnife;
27 | import butterknife.OnClick;
28 | import butterknife.Unbinder;
29 | import io.reactivex.android.schedulers.AndroidSchedulers;
30 | import io.reactivex.disposables.Disposable;
31 | import io.reactivex.schedulers.Schedulers;
32 |
33 | /**
34 | * The localize Fragment.
35 | */
36 | public class LocalizeFragment extends Fragment {
37 |
38 | @NonNull
39 | private static final String TAG = "LocalizeFragment";
40 |
41 | @Nullable
42 | private LocalizeScreen screen;
43 | @Nullable
44 | private LocalizeMachine machine;
45 |
46 | @Nullable
47 | private Unbinder unbinder;
48 |
49 | @BindView(R.id.startLocalizeButton)
50 | Button startLocalizeButton;
51 |
52 | @BindView(R.id.infoTextView)
53 | TextView infoTextView;
54 |
55 | @BindView(R.id.warningImage)
56 | ImageView warningImage;
57 |
58 | @BindView(R.id.infoImageView)
59 | ImageView infoImageView;
60 |
61 | @BindView(R.id.progressAnimationView)
62 | LottieAnimationView progressAnimationView;
63 |
64 | @Nullable
65 | private Disposable disposable;
66 |
67 | @Nullable
68 | private MediaPlayer mediaPlayer;
69 |
70 | @Override
71 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
72 | Bundle savedInstanceState) {
73 | View view = inflater.inflate(R.layout.fragment_localize, container, false);
74 | unbinder = ButterKnife.bind(this, view);
75 | return view;
76 | }
77 |
78 | @Override
79 | public void onResume() {
80 | super.onResume();
81 |
82 | infoTextView.setVisibility(View.INVISIBLE);
83 | startLocalizeButton.setVisibility(View.INVISIBLE);
84 | warningImage.setVisibility(View.INVISIBLE);
85 | infoImageView.setVisibility(View.INVISIBLE);
86 | progressAnimationView.setVisibility(View.INVISIBLE);
87 |
88 | if (machine != null) {
89 | disposable = machine.localizeState()
90 | .subscribeOn(Schedulers.io())
91 | .observeOn(AndroidSchedulers.mainThread())
92 | .subscribe(this::onLocalizeStateChanged);
93 | }
94 | }
95 |
96 | @Override
97 | public void onPause() {
98 | if (disposable != null && !disposable.isDisposed()) {
99 | disposable.dispose();
100 | }
101 |
102 | if (mediaPlayer != null) {
103 | mediaPlayer.release();
104 | mediaPlayer = null;
105 | }
106 |
107 | super.onPause();
108 | }
109 |
110 | @Override
111 | public void onDestroyView() {
112 | if (unbinder != null) {
113 | unbinder.unbind();
114 | }
115 | super.onDestroyView();
116 | }
117 |
118 | @OnClick(R.id.startLocalizeButton)
119 | public void onClickStartLocalize() {
120 | if (machine != null) {
121 | machine.post(LocalizeEvent.START_LOCALIZE);
122 | }
123 | }
124 |
125 | @NonNull
126 | static LocalizeFragment newInstance(@NonNull LocalizeScreen screen, @NonNull LocalizeMachine machine) {
127 | LocalizeFragment fragment = new LocalizeFragment();
128 | fragment.screen = screen;
129 | fragment.machine = machine;
130 | return fragment;
131 | }
132 |
133 | private void playSound(@RawRes int soundResId, boolean playInLoop) {
134 | if (mediaPlayer != null) {
135 | mediaPlayer.release();
136 | }
137 |
138 | FragmentActivity activity = getActivity();
139 | if (activity != null) {
140 | mediaPlayer = MediaPlayer.create(activity, soundResId);
141 | mediaPlayer.setLooping(playInLoop);
142 | mediaPlayer.start();
143 | }
144 | }
145 |
146 | private void onLocalizeStateChanged(@NonNull LocalizeState localizeState) {
147 | Log.d(TAG, "onLocalizeStateChanged: " + localizeState);
148 |
149 | switch (localizeState) {
150 | case IDLE:
151 | infoTextView.setVisibility(View.INVISIBLE);
152 | startLocalizeButton.setVisibility(View.INVISIBLE);
153 | warningImage.setVisibility(View.GONE);
154 | infoImageView.setVisibility(View.INVISIBLE);
155 | progressAnimationView.setVisibility(View.INVISIBLE);
156 | break;
157 | case BRIEFING:
158 | infoTextView.setVisibility(View.VISIBLE);
159 | startLocalizeButton.setVisibility(View.VISIBLE);
160 | warningImage.setVisibility(View.GONE);
161 | infoImageView.setVisibility(View.INVISIBLE);
162 | progressAnimationView.setVisibility(View.INVISIBLE);
163 | infoTextView.setText(R.string.briefing_text);
164 | break;
165 | case ADVICES:
166 | infoTextView.setVisibility(View.VISIBLE);
167 | startLocalizeButton.setVisibility(View.INVISIBLE);
168 | warningImage.setVisibility(View.GONE);
169 | infoImageView.setVisibility(View.VISIBLE);
170 | progressAnimationView.setVisibility(View.INVISIBLE);
171 | infoTextView.setText(R.string.advices_text);
172 | infoImageView.setImageResource(R.drawable.hiding);
173 | break;
174 | case LOADING_MAP:
175 | infoTextView.setVisibility(View.VISIBLE);
176 | startLocalizeButton.setVisibility(View.INVISIBLE);
177 | warningImage.setVisibility(View.GONE);
178 | infoImageView.setVisibility(View.INVISIBLE);
179 | progressAnimationView.setVisibility(View.VISIBLE);
180 | infoTextView.setText(R.string.localize_loading_map_text);
181 | playSound(R.raw.processing, true);
182 | break;
183 | case LOCALIZING:
184 | infoTextView.setVisibility(View.VISIBLE);
185 | startLocalizeButton.setVisibility(View.INVISIBLE);
186 | warningImage.setVisibility(View.GONE);
187 | infoImageView.setVisibility(View.INVISIBLE);
188 | progressAnimationView.setVisibility(View.VISIBLE);
189 | infoTextView.setText(R.string.localize_localizing_text);
190 | playSound(R.raw.sonar, true);
191 | break;
192 | case ERROR:
193 | infoTextView.setVisibility(View.VISIBLE);
194 | startLocalizeButton.setVisibility(View.VISIBLE);
195 | warningImage.setVisibility(View.VISIBLE);
196 | infoImageView.setVisibility(View.INVISIBLE);
197 | progressAnimationView.setVisibility(View.INVISIBLE);
198 | infoTextView.setText(R.string.error_text);
199 | playSound(R.raw.error, false);
200 | break;
201 | case SUCCESS:
202 | infoTextView.setVisibility(View.VISIBLE);
203 | startLocalizeButton.setVisibility(View.INVISIBLE);
204 | warningImage.setVisibility(View.GONE);
205 | infoImageView.setVisibility(View.VISIBLE);
206 | progressAnimationView.setVisibility(View.INVISIBLE);
207 | infoTextView.setText(R.string.success_text);
208 | infoImageView.setImageResource(R.drawable.ic_check);
209 | playSound(R.raw.success, false);
210 | break;
211 | case END:
212 | if (screen != null) {
213 | screen.onLocalizeEnd();
214 | }
215 | break;
216 | }
217 | }
218 | }
219 |
--------------------------------------------------------------------------------
/app/src/main/java/com/softbankrobotics/sample/returntomapframe/menu/MenuActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 Softbank Robotics Europe
3 | * See COPYING for the license
4 | */
5 | package com.softbankrobotics.sample.returntomapframe.menu;
6 |
7 | import android.content.Intent;
8 | import android.os.Bundle;
9 | import android.util.Log;
10 | import android.widget.RadioButton;
11 |
12 | import com.aldebaran.qi.sdk.QiContext;
13 | import com.aldebaran.qi.sdk.QiSDK;
14 | import com.aldebaran.qi.sdk.RobotLifecycleCallbacks;
15 | import com.aldebaran.qi.sdk.builder.ChatBuilder;
16 | import com.aldebaran.qi.sdk.builder.QiChatbotBuilder;
17 | import com.aldebaran.qi.sdk.builder.TopicBuilder;
18 | import com.aldebaran.qi.sdk.design.activity.RobotActivity;
19 | import com.aldebaran.qi.sdk.object.conversation.AutonomousReactionImportance;
20 | import com.aldebaran.qi.sdk.object.conversation.AutonomousReactionValidity;
21 | import com.aldebaran.qi.sdk.object.conversation.Bookmark;
22 | import com.aldebaran.qi.sdk.object.conversation.BookmarkStatus;
23 | import com.aldebaran.qi.sdk.object.conversation.Chat;
24 | import com.aldebaran.qi.sdk.object.conversation.QiChatVariable;
25 | import com.aldebaran.qi.sdk.object.conversation.QiChatbot;
26 | import com.aldebaran.qi.sdk.object.conversation.Topic;
27 | import com.softbankrobotics.sample.returntomapframe.R;
28 | import com.softbankrobotics.sample.returntomapframe.core.MapManager;
29 | import com.softbankrobotics.sample.returntomapframe.localization.LocalizationActivity;
30 | import com.softbankrobotics.sample.returntomapframe.mapping.MappingActivity;
31 |
32 | import java.util.Map;
33 | import java.util.concurrent.TimeUnit;
34 | import java.util.concurrent.atomic.AtomicBoolean;
35 |
36 | import androidx.annotation.NonNull;
37 | import androidx.annotation.Nullable;
38 | import butterknife.BindView;
39 | import butterknife.ButterKnife;
40 | import butterknife.OnClick;
41 | import io.reactivex.Single;
42 | import io.reactivex.disposables.Disposable;
43 | import io.reactivex.schedulers.Schedulers;
44 |
45 | /**
46 | * The menu Activity.
47 | */
48 | public class MenuActivity extends RobotActivity implements RobotLifecycleCallbacks {
49 |
50 | @NonNull
51 | private static final String TAG = "MenuActivity";
52 |
53 | @NonNull
54 | private static final String START_BOOKMARK_NAME = "start";
55 | @NonNull
56 | private static final String CREATE_BOOKMARK_NAME = "create";
57 | @NonNull
58 | private static final String CREATE_END_BOOKMARK_NAME = "create_end";
59 | @NonNull
60 | private static final String USE_BOOKMARK_NAME = "use";
61 | @NonNull
62 | private static final String USE_END_BOOKMARK_NAME = "use_end";
63 | @NonNull
64 | private static final String MAP_BOOKMARK_NAME = "map";
65 | @NonNull
66 | private static final String START_TIMER_BOOKMARK_NAME = "start_timer";
67 | @NonNull
68 | private static final String STOP_TIMER_BOOKMARK_NAME = "stop_timer";
69 |
70 | @BindView(R.id.createMapButton)
71 | RadioButton createMapButton;
72 |
73 | @BindView(R.id.useMapButton)
74 | RadioButton useMapButton;
75 |
76 | @Nullable
77 | private Map bookmarks;
78 | @Nullable
79 | private QiChatbot qiChatbot;
80 | @Nullable
81 | private Chat chat;
82 |
83 | @Nullable
84 | private Disposable timerDisposable;
85 | @NonNull
86 | private final AtomicBoolean shouldRepeatWithTimer = new AtomicBoolean(true);
87 |
88 | @Override
89 | protected void onCreate(Bundle savedInstanceState) {
90 | super.onCreate(savedInstanceState);
91 |
92 | setContentView(R.layout.activity_menu);
93 | ButterKnife.bind(this);
94 |
95 | QiSDK.register(this, this);
96 | }
97 |
98 | @Override
99 | protected void onResume() {
100 | super.onResume();
101 |
102 | createMapButton.setChecked(false);
103 | useMapButton.setChecked(false);
104 |
105 | createMapButton.setEnabled(true);
106 | useMapButton.setEnabled(false);
107 | }
108 |
109 | @Override
110 | protected void onDestroy() {
111 | QiSDK.unregister(this, this);
112 | super.onDestroy();
113 | }
114 |
115 | @Override
116 | public void onRobotFocusGained(QiContext qiContext) {
117 | shouldRepeatWithTimer.set(true);
118 |
119 | Topic topic = TopicBuilder.with(qiContext)
120 | .withResource(R.raw.menu)
121 | .build();
122 |
123 | bookmarks = topic.getBookmarks();
124 |
125 | qiChatbot = QiChatbotBuilder.with(qiContext)
126 | .withTopic(topic)
127 | .build();
128 |
129 | if (qiChatbot != null) {
130 | QiChatVariable proposalVariable = qiChatbot.variable("proposal");
131 |
132 | // Change the speech and enable/disable the "use map" option, depending on the map existence.
133 | if (MapManager.hasMap(getApplicationContext())) {
134 | proposalVariable.setValue(getString(R.string.menu_sentence_with_map));
135 | runOnUiThread(() -> useMapButton.setEnabled(true));
136 | } else if (bookmarks != null) {
137 | proposalVariable.setValue(getString(R.string.menu_sentence_no_map));
138 | BookmarkStatus bookmarkStatus = qiChatbot.bookmarkStatus(bookmarks.get(MAP_BOOKMARK_NAME));
139 | bookmarkStatus.setEnabled(false);
140 | }
141 |
142 | qiChatbot.addOnBookmarkReachedListener(bookmark -> {
143 | switch (bookmark.getName()) {
144 | case CREATE_BOOKMARK_NAME:
145 | runOnUiThread(() -> createMapButton.setChecked(true));
146 | disableButtons();
147 | break;
148 | case MAP_BOOKMARK_NAME:
149 | runOnUiThread(() -> useMapButton.setChecked(true));
150 | disableButtons();
151 | break;
152 | case CREATE_END_BOOKMARK_NAME:
153 | startMappingActivity();
154 | break;
155 | case USE_END_BOOKMARK_NAME:
156 | startLocalizationActivity();
157 | break;
158 | case START_TIMER_BOOKMARK_NAME:
159 | if (shouldRepeatWithTimer.getAndSet(false)) {
160 | startTimer();
161 | }
162 | break;
163 | case STOP_TIMER_BOOKMARK_NAME:
164 | stopTimer();
165 | break;
166 | }
167 | });
168 | }
169 |
170 | chat = ChatBuilder.with(qiContext)
171 | .withChatbot(qiChatbot)
172 | .build();
173 |
174 | chat.addOnStartedListener(() -> goToBookmark(START_BOOKMARK_NAME, AutonomousReactionImportance.LOW));
175 |
176 | chat.async().run();
177 | }
178 |
179 | @Override
180 | public void onRobotFocusLost() {
181 | stopTimer();
182 |
183 | bookmarks = null;
184 | if (qiChatbot != null) {
185 | qiChatbot.removeAllOnBookmarkReachedListeners();
186 | qiChatbot = null;
187 | }
188 | if (chat != null) {
189 | chat.removeAllOnStartedListeners();
190 | chat = null;
191 | }
192 | }
193 |
194 | @Override
195 | public void onRobotFocusRefused(String reason) {
196 | Log.e(TAG, "onRobotFocusRefused: " + reason);
197 | }
198 |
199 | @OnClick(R.id.createMapButton)
200 | public void onClickCreateMap() {
201 | disableButtons();
202 | if (!goToBookmark(CREATE_BOOKMARK_NAME, AutonomousReactionImportance.HIGH)) {
203 | startMappingActivity();
204 | }
205 | }
206 |
207 | @OnClick(R.id.useMapButton)
208 | public void onClickUseMap() {
209 | disableButtons();
210 | if (!goToBookmark(USE_BOOKMARK_NAME, AutonomousReactionImportance.HIGH)) {
211 | startLocalizationActivity();
212 | }
213 | }
214 |
215 | @OnClick(R.id.closeButton)
216 | public void onCloseClicked() {
217 | finishAffinity();
218 | }
219 |
220 | private void disableButtons() {
221 | runOnUiThread(() -> {
222 | createMapButton.setEnabled(false);
223 | useMapButton.setEnabled(false);
224 | });
225 | }
226 |
227 | private void startLocalizationActivity() {
228 | startActivity(new Intent(this, LocalizationActivity.class));
229 | }
230 |
231 | private void startMappingActivity() {
232 | startActivity(new Intent(this, MappingActivity.class));
233 | }
234 |
235 | private boolean goToBookmark(@NonNull String name, @NonNull AutonomousReactionImportance importance) {
236 | Bookmark bookmark;
237 | if ((bookmarks == null)
238 | || ((bookmark = bookmarks.get(name)) == null)
239 | || (qiChatbot == null)) {
240 | return false;
241 | }
242 |
243 | qiChatbot.async().goToBookmark(bookmark, importance, AutonomousReactionValidity.IMMEDIATE);
244 | return true;
245 | }
246 |
247 | private void startTimer() {
248 | timerDisposable = Single.timer(5, TimeUnit.SECONDS)
249 | .observeOn(Schedulers.io())
250 | .subscribeOn(Schedulers.io())
251 | .subscribe(ignored -> {
252 | stopTimer();
253 | goToBookmark(START_BOOKMARK_NAME, AutonomousReactionImportance.LOW);
254 | });
255 | }
256 |
257 | private void stopTimer() {
258 | if (timerDisposable != null && !timerDisposable.isDisposed()) {
259 | timerDisposable.dispose();
260 | }
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/app/src/main/assets/lottie/splashy_loader.json:
--------------------------------------------------------------------------------
1 | {"v":"4.6.3","fr":29.9700012207031,"ip":1.00000004073083,"op":67.000002728966,"w":600,"h":600,"nm":"Splash 3","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Splash 7","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-451.084},"p":{"a":0,"k":[295.083,97.911,0]},"a":{"a":0,"k":[107.25,-230.25,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":52,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":54,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":57,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":59.0000024031193}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":52.0000021180034,"op":61.0000024845809,"st":31.0000012626559,"bm":0,"sr":1},{"ddd":0,"ind":2,"ty":4,"nm":"Splash 6","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-262},"p":{"a":0,"k":[305.083,107.911,0]},"a":{"a":0,"k":[107.25,-230.25,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":54,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":56,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":59,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":61.0000024845809}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":54.0000021994651,"op":63.0000025660426,"st":33.0000013441176,"bm":0,"sr":1},{"ddd":0,"ind":3,"ty":4,"nm":"Splash 5","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-191},"p":{"a":0,"k":[287.149,139.465,0]},"a":{"a":0,"k":[127.684,-254.11,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":50,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":52,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":55,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":57.0000023216576}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":50.0000020365418,"op":59.0000024031193,"st":29.0000011811942,"bm":0,"sr":1},{"ddd":0,"ind":4,"ty":4,"nm":"Splash 4","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-11},"p":{"a":0,"k":[323.383,57.538,0]},"a":{"a":0,"k":[130.011,-258.056,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":52,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":54,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":57,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":59.0000024031193}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":52.0000021180034,"op":61.0000024845809,"st":31.0000012626559,"bm":0,"sr":1},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 3","parent":13,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[4.729,-8.375,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0]],"o":[[0,0]],"v":[[-622,101]],"c":false}},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"ix":2,"mn":"ADBE Vector Group"},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":0,"s":[{"i":[[0,-0.414],[0.414,0],[0.114,0.27],[0.01,0.042],[0.003,0.037],[0,0.013],[0,0.008],[-0.001,0.017],[-0.006,0.03],[-0.365,0]],"o":[[0,0.414],[-0.311,0],[-0.016,-0.039],[-0.008,-0.035],[-0.001,-0.013],[0,-0.008],[0,-0.018],[0.002,-0.031],[0.067,-0.345],[0.414,0]],"v":[[1.75,-176.75],[1,-176],[0.309,-176.459],[0.269,-176.581],[0.253,-176.688],[0.25,-176.726],[0.25,-176.75],[0.252,-176.802],[0.264,-176.894],[1,-177.5]],"c":true}],"e":[{"i":[[0,-38.5],[38.5,0],[10.561,25.068],[0.901,3.908],[0.278,3.394],[0.037,1.201],[0,0.733],[-0.11,1.6],[-0.542,2.79],[-33.924,0]],"o":[[0,38.5],[-28.909,0],[-1.528,-3.626],[-0.747,-3.238],[-0.097,-1.185],[-0.022,-0.727],[0,-1.628],[0.199,-2.898],[6.24,-32.099],[38.5,0]],"v":[[70.71,-176.75],[1,-107.04],[-63.269,-149.706],[-66.928,-161.023],[-68.474,-170.98],[-68.676,-174.56],[-68.71,-176.75],[-68.544,-181.592],[-67.427,-190.129],[1,-246.46]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0,-38.5],[38.5,0],[10.561,25.068],[0.901,3.908],[0.278,3.394],[0.037,1.201],[0,0.733],[-0.11,1.6],[-0.542,2.79],[-33.924,0]],"o":[[0,38.5],[-28.909,0],[-1.528,-3.626],[-0.747,-3.238],[-0.097,-1.185],[-0.022,-0.727],[0,-1.628],[0.199,-2.898],[6.24,-32.099],[38.5,0]],"v":[[70.71,-176.75],[1,-107.04],[-63.269,-149.706],[-66.928,-161.023],[-68.474,-170.98],[-68.676,-174.56],[-68.71,-176.75],[-68.544,-181.592],[-67.427,-190.129],[1,-246.46]],"c":true}],"e":[{"i":[[0,-24.024],[24.025,0],[6.59,15.643],[0.562,2.439],[0.174,2.118],[0.023,0.75],[0,0.457],[-0.068,0.998],[-0.338,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-0.953,-2.263],[-0.466,-2.021],[-0.061,-0.74],[-0.014,-0.454],[0,-1.016],[0.124,-1.808],[3.894,-20.03],[24.024,0]],"v":[[44.5,-176.75],[1,-133.25],[-39.105,-159.874],[-41.389,-166.936],[-42.353,-173.149],[-42.479,-175.383],[-42.5,-176.75],[-42.397,-179.771],[-41.7,-185.099],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[0,-24.024],[24.025,0],[6.59,15.643],[0.562,2.439],[0.174,2.118],[0.023,0.75],[0,0.457],[-0.068,0.998],[-0.338,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-0.953,-2.263],[-0.466,-2.021],[-0.061,-0.74],[-0.014,-0.454],[0,-1.016],[0.124,-1.808],[3.894,-20.03],[24.024,0]],"v":[[44.5,-176.75],[1,-133.25],[-39.105,-159.874],[-41.389,-166.936],[-42.353,-173.149],[-42.479,-175.383],[-42.5,-176.75],[-42.397,-179.771],[-41.7,-185.099],[1,-220.25]],"c":true}],"e":[{"i":[[0,-24.024],[24.024,0],[14.315,15.643],[1.284,2.439],[0.411,2.118],[0.055,0.75],[0,0.457],[-0.163,0.998],[-0.78,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-2.071,-2.263],[-1.064,-2.021],[-0.143,-0.74],[-0.034,-0.454],[0,-1.016],[0.295,-1.808],[8.969,-20.03],[24.024,0]],"v":[[38.063,-176.75],[1,-133.25],[-62.336,-159.874],[-67.413,-166.936],[-69.65,-173.149],[-69.949,-175.383],[-70,-176.75],[-69.753,-179.771],[-68.126,-185.099],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[0,-24.024],[24.024,0],[14.315,15.643],[1.284,2.439],[0.411,2.118],[0.055,0.75],[0,0.457],[-0.163,0.998],[-0.78,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-2.071,-2.263],[-1.064,-2.021],[-0.143,-0.74],[-0.034,-0.454],[0,-1.016],[0.295,-1.808],[8.969,-20.03],[24.024,0]],"v":[[38.063,-176.75],[1,-133.25],[-62.336,-159.874],[-67.413,-166.936],[-69.65,-173.149],[-69.949,-175.383],[-70,-176.75],[-69.753,-179.771],[-68.126,-185.099],[1,-220.25]],"c":true}],"e":[{"i":[[3.937,-24.75],[24.791,10.086],[26.888,-7.416],[4.71,-1.015],[0.894,2.746],[3.258,0.928],[0.486,1.089],[-0.523,2.769],[-3.31,4.458],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-6.108,1.685],[-5.708,1.23],[-0.492,-1.51],[-2.261,-0.644],[-1.025,-2.295],[0.727,-3.849],[21.022,-28.316],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-112.773,-134.745],[-115.701,-140.777],[-142.813,-129.799],[-119.515,-152.225],[-156.245,-134.275],[-142.384,-147.783],[-147.76,-151.014],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":15,"s":[{"i":[[3.937,-24.75],[24.791,10.086],[26.888,-7.416],[4.71,-1.015],[0.894,2.746],[3.258,0.928],[0.486,1.089],[-0.523,2.769],[-3.31,4.458],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-6.108,1.685],[-5.708,1.23],[-0.492,-1.51],[-2.261,-0.644],[-1.025,-2.295],[0.727,-3.849],[21.022,-28.316],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-112.773,-134.745],[-115.701,-140.777],[-142.813,-129.799],[-119.515,-152.225],[-156.245,-134.275],[-142.384,-147.783],[-147.76,-151.014],[1,-220.25]],"c":true}],"e":[{"i":[[3.937,-24.75],[24.791,10.086],[75.901,-44.488],[4.785,0.557],[2.786,1.657],[3.258,0.928],[0.797,0.747],[1.267,1.798],[-2.7,4.852],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-5.467,3.204],[-6.56,-0.763],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-1.706,-2.421],[46.978,-84.44],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-178.164,-93.595],[-165.774,-108.983],[-207.061,-72.551],[-185.397,-102.972],[-205.964,-83.28],[-166.995,-136.02],[-198.497,-103.554],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":18,"s":[{"i":[[3.937,-24.75],[24.791,10.086],[75.901,-44.488],[4.785,0.557],[2.786,1.657],[3.258,0.928],[0.797,0.747],[1.267,1.798],[-2.7,4.852],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-5.467,3.204],[-6.56,-0.763],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-1.706,-2.421],[46.978,-84.44],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-178.164,-93.595],[-165.774,-108.983],[-207.061,-72.551],[-185.397,-102.972],[-205.964,-83.28],[-166.995,-136.02],[-198.497,-103.554],[1,-220.25]],"c":true}],"e":[{"i":[[3.937,-24.75],[25.212,8.981],[6.062,-0.333],[4.691,1.099],[2.786,1.657],[3.258,0.928],[0.797,0.747],[2.151,0.459],[1.537,1.127],[-191.635,1.35]],"o":[[-3.775,23.726],[-174.984,-62.332],[-6.327,0.347],[-4.13,-0.968],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-4.565,-0.975],[-3.629,-2.662],[24.024,-0.169]],"v":[[46.062,-169.25],[1,-133.25],[-219.478,24.635],[-205.5,-31.17],[-221.353,-1.31],[-208.694,-54.13],[-222.458,-18.335],[-219.05,-42.263],[-225.237,-35.722],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"n":"0p833_0p833_0p333_0","t":22,"s":[{"i":[[3.937,-24.75],[25.212,8.981],[6.062,-0.333],[4.691,1.099],[2.786,1.657],[3.258,0.928],[0.797,0.747],[2.151,0.459],[1.537,1.127],[-191.635,1.35]],"o":[[-3.775,23.726],[-174.984,-62.332],[-6.327,0.347],[-4.13,-0.968],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-4.565,-0.975],[-3.629,-2.662],[24.024,-0.169]],"v":[[46.062,-169.25],[1,-133.25],[-219.478,24.635],[-205.5,-31.17],[-221.353,-1.31],[-208.694,-54.13],[-222.458,-18.335],[-219.05,-42.263],[-225.237,-35.722],[1,-220.25]],"c":true}],"e":[{"i":[[3.937,-24.75],[25.212,8.981],[6.062,-0.333],[4.691,1.099],[2.786,1.657],[3.258,0.928],[0.797,0.747],[2.151,0.459],[1.537,1.127],[-191.635,1.35]],"o":[[-3.775,23.726],[-174.984,-62.332],[-6.327,0.347],[-4.13,-0.968],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-4.565,-0.975],[-3.629,-2.662],[24.024,-0.169]],"v":[[46.062,-169.25],[1,-133.25],[-219.478,24.635],[-205.5,-31.17],[-221.353,-1.31],[-208.694,-54.13],[-222.458,-18.335],[-219.05,-42.263],[-225.237,-35.722],[1,-220.25]],"c":true}]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"n":"0p667_1_0p167_0p167","t":26,"s":[{"i":[[3.937,-24.75],[25.212,8.981],[6.062,-0.333],[4.691,1.099],[2.786,1.657],[3.258,0.928],[0.797,0.747],[2.151,0.459],[1.537,1.127],[-191.635,1.35]],"o":[[-3.775,23.726],[-174.984,-62.332],[-6.327,0.347],[-4.13,-0.968],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-4.565,-0.975],[-3.629,-2.662],[24.024,-0.169]],"v":[[46.062,-169.25],[1,-133.25],[-219.478,24.635],[-205.5,-31.17],[-221.353,-1.31],[-208.694,-54.13],[-222.458,-18.335],[-219.05,-42.263],[-225.237,-35.722],[1,-220.25]],"c":true}],"e":[{"i":[[3.937,-24.75],[24.791,10.086],[75.901,-44.488],[4.785,0.557],[2.786,1.657],[3.258,0.928],[0.797,0.747],[1.267,1.798],[-2.7,4.852],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-5.467,3.204],[-6.56,-0.763],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-1.706,-2.421],[46.978,-84.44],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-178.164,-93.595],[-165.774,-108.983],[-207.061,-72.551],[-185.397,-102.972],[-205.964,-83.28],[-166.995,-136.02],[-198.497,-103.554],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":32,"s":[{"i":[[3.937,-24.75],[24.791,10.086],[75.901,-44.488],[4.785,0.557],[2.786,1.657],[3.258,0.928],[0.797,0.747],[1.267,1.798],[-2.7,4.852],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-5.467,3.204],[-6.56,-0.763],[-1.365,-0.812],[-2.261,-0.644],[-3.843,-3.606],[-1.706,-2.421],[46.978,-84.44],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-178.164,-93.595],[-165.774,-108.983],[-207.061,-72.551],[-185.397,-102.972],[-205.964,-83.28],[-166.995,-136.02],[-198.497,-103.554],[1,-220.25]],"c":true}],"e":[{"i":[[3.937,-24.75],[24.791,10.086],[26.888,-7.416],[4.71,-1.015],[0.894,2.746],[3.258,0.928],[0.486,1.089],[-0.523,2.769],[-3.31,4.458],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-6.108,1.685],[-5.708,1.23],[-0.492,-1.51],[-2.261,-0.644],[-1.025,-2.295],[0.727,-3.849],[21.022,-28.316],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-112.773,-134.745],[-115.701,-140.777],[-142.813,-129.799],[-119.515,-152.225],[-156.245,-134.275],[-142.384,-147.783],[-147.76,-151.014],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":38,"s":[{"i":[[3.937,-24.75],[24.791,10.086],[26.888,-7.416],[4.71,-1.015],[0.894,2.746],[3.258,0.928],[0.486,1.089],[-0.523,2.769],[-3.31,4.458],[-54.694,0]],"o":[[-3.775,23.726],[-47.086,-19.156],[-6.108,1.685],[-5.708,1.23],[-0.492,-1.51],[-2.261,-0.644],[-1.025,-2.295],[0.727,-3.849],[21.022,-28.316],[24.024,0]],"v":[[46.063,-169.25],[1,-133.25],[-112.773,-134.745],[-115.701,-140.777],[-142.813,-129.799],[-119.515,-152.225],[-156.245,-134.275],[-142.384,-147.783],[-147.76,-151.014],[1,-220.25]],"c":true}],"e":[{"i":[[0,-24.024],[24.024,0],[14.315,15.643],[1.284,2.439],[0.411,2.118],[0.055,0.75],[0,0.457],[-0.163,0.998],[-0.78,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-2.071,-2.263],[-1.064,-2.021],[-0.143,-0.74],[-0.034,-0.454],[0,-1.016],[0.295,-1.808],[8.969,-20.03],[24.024,0]],"v":[[38.063,-176.75],[1,-133.25],[-62.336,-159.874],[-67.413,-166.936],[-69.65,-173.149],[-69.949,-175.383],[-70,-176.75],[-69.753,-179.771],[-68.126,-185.099],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":41,"s":[{"i":[[0,-24.024],[24.024,0],[14.315,15.643],[1.284,2.439],[0.411,2.118],[0.055,0.75],[0,0.457],[-0.163,0.998],[-0.78,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-2.071,-2.263],[-1.064,-2.021],[-0.143,-0.74],[-0.034,-0.454],[0,-1.016],[0.295,-1.808],[8.969,-20.03],[24.024,0]],"v":[[38.063,-176.75],[1,-133.25],[-62.336,-159.874],[-67.413,-166.936],[-69.65,-173.149],[-69.949,-175.383],[-70,-176.75],[-69.753,-179.771],[-68.126,-185.099],[1,-220.25]],"c":true}],"e":[{"i":[[0,-24.024],[24.025,0],[6.59,15.643],[0.562,2.439],[0.174,2.118],[0.023,0.75],[0,0.457],[-0.068,0.998],[-0.338,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-0.953,-2.263],[-0.466,-2.021],[-0.061,-0.74],[-0.014,-0.454],[0,-1.016],[0.124,-1.808],[3.894,-20.03],[24.024,0]],"v":[[44.5,-176.75],[1,-133.25],[-39.105,-159.874],[-41.389,-166.936],[-42.353,-173.149],[-42.479,-175.383],[-42.5,-176.75],[-42.397,-179.771],[-41.7,-185.099],[1,-220.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":45,"s":[{"i":[[0,-24.024],[24.025,0],[6.59,15.643],[0.562,2.439],[0.174,2.118],[0.023,0.75],[0,0.457],[-0.068,0.998],[-0.338,1.741],[-21.169,0]],"o":[[0,24.024],[-18.04,0],[-0.953,-2.263],[-0.466,-2.021],[-0.061,-0.74],[-0.014,-0.454],[0,-1.016],[0.124,-1.808],[3.894,-20.03],[24.024,0]],"v":[[44.5,-176.75],[1,-133.25],[-39.105,-159.874],[-41.389,-166.936],[-42.353,-173.149],[-42.479,-175.383],[-42.5,-176.75],[-42.397,-179.771],[-41.7,-185.099],[1,-220.25]],"c":true}],"e":[{"i":[[0,-38.5],[38.5,0],[10.561,25.068],[0.901,3.908],[0.278,3.394],[0.037,1.201],[0,0.733],[-0.11,1.6],[-0.542,2.79],[-33.924,0]],"o":[[0,38.5],[-28.909,0],[-1.528,-3.626],[-0.747,-3.238],[-0.097,-1.185],[-0.022,-0.727],[0,-1.628],[0.199,-2.898],[6.24,-32.099],[38.5,0]],"v":[[70.71,-176.75],[1,-107.04],[-63.269,-149.706],[-66.928,-161.023],[-68.474,-170.98],[-68.676,-174.56],[-68.71,-176.75],[-68.544,-181.592],[-67.427,-190.129],[1,-246.46]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":47,"s":[{"i":[[0,-38.5],[38.5,0],[10.561,25.068],[0.901,3.908],[0.278,3.394],[0.037,1.201],[0,0.733],[-0.11,1.6],[-0.542,2.79],[-33.924,0]],"o":[[0,38.5],[-28.909,0],[-1.528,-3.626],[-0.747,-3.238],[-0.097,-1.185],[-0.022,-0.727],[0,-1.628],[0.199,-2.898],[6.24,-32.099],[38.5,0]],"v":[[70.71,-176.75],[1,-107.04],[-63.269,-149.706],[-66.928,-161.023],[-68.474,-170.98],[-68.676,-174.56],[-68.71,-176.75],[-68.544,-181.592],[-67.427,-190.129],[1,-246.46]],"c":true}],"e":[{"i":[[0,-0.414],[0.414,0],[0.114,0.27],[0.01,0.042],[0.003,0.037],[0,0.013],[0,0.008],[-0.001,0.017],[-0.006,0.03],[-0.365,0]],"o":[[0,0.414],[-0.311,0],[-0.016,-0.039],[-0.008,-0.035],[-0.001,-0.013],[0,-0.008],[0,-0.018],[0.002,-0.031],[0.067,-0.345],[0.414,0]],"v":[[1.75,-176.75],[1,-176],[0.309,-176.459],[0.269,-176.581],[0.253,-176.688],[0.25,-176.726],[0.25,-176.75],[0.252,-176.802],[0.264,-176.894],[1,-177.5]],"c":true}]},{"t":55.0000022401959}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":0,"op":60.0000024438501,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":6,"ty":4,"nm":"Splash 8","parent":13,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":181},"p":{"a":0,"k":[-119.127,-211.088,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[94.47,-140.13],[94.13,-140.03],[94.03,-140.37],[94.37,-140.47]],"c":true}],"e":[{"i":[[2.591,-4.756],[4.756,2.591],[-2.591,4.756],[-4.757,-2.591]],"o":[[-2.591,4.756],[-4.756,-2.591],[2.591,-4.756],[4.757,2.591]],"v":[[106.279,-141.477],[92.977,-137.555],[89.055,-150.856],[102.356,-154.778]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":33,"s":[{"i":[[2.591,-4.756],[4.756,2.591],[-2.591,4.756],[-4.757,-2.591]],"o":[[-2.591,4.756],[-4.756,-2.591],[2.591,-4.756],[4.757,2.591]],"v":[[106.279,-141.477],[92.977,-137.555],[89.055,-150.856],[102.356,-154.778]],"c":true}],"e":[{"i":[[2.7,-4.695],[1.391,0.912],[-8.305,37.856],[-4.757,-2.591]],"o":[[-17.529,30.477],[-1.727,-1.133],[1.161,-5.29],[4.757,2.591]],"v":[[105.529,-139.977],[49.727,-77.055],[88.305,-149.356],[102.606,-155.028]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":36,"s":[{"i":[[2.7,-4.695],[1.391,0.912],[-8.305,37.856],[-4.757,-2.591]],"o":[[-17.529,30.477],[-1.727,-1.133],[1.161,-5.29],[4.757,2.591]],"v":[[105.529,-139.977],[49.727,-77.055],[88.305,-149.356],[102.606,-155.028]],"c":true}],"e":[{"i":[[2.7,-4.695],[1.391,0.912],[-8.305,37.856],[-4.757,-2.591]],"o":[[-17.529,30.477],[-1.727,-1.133],[1.161,-5.29],[4.757,2.591]],"v":[[105.529,-139.977],[49.727,-77.055],[88.305,-149.356],[102.606,-155.028]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":37,"s":[{"i":[[2.7,-4.695],[1.391,0.912],[-8.305,37.856],[-4.757,-2.591]],"o":[[-17.529,30.477],[-1.727,-1.133],[1.161,-5.29],[4.757,2.591]],"v":[[105.529,-139.977],[49.727,-77.055],[88.305,-149.356],[102.606,-155.028]],"c":true}],"e":[{"i":[[2.591,-4.756],[4.756,2.591],[-2.591,4.756],[-4.757,-2.591]],"o":[[-2.591,4.756],[-4.756,-2.591],[2.591,-4.756],[4.757,2.591]],"v":[[106.279,-141.477],[92.977,-137.555],[89.055,-150.856],[102.356,-154.778]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":41,"s":[{"i":[[2.591,-4.756],[4.756,2.591],[-2.591,4.756],[-4.757,-2.591]],"o":[[-2.591,4.756],[-4.756,-2.591],[2.591,-4.756],[4.757,2.591]],"v":[[106.279,-141.477],[92.977,-137.555],[89.055,-150.856],[102.356,-154.778]],"c":true}],"e":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[99.47,-145.13],[99.13,-145.03],[99.03,-145.37],[99.369,-145.47]],"c":true}]},{"t":44.0000017921567}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":31.0000012626559,"op":46.0000018736184,"st":10.0000004073083,"bm":0,"sr":1},{"ddd":0,"ind":7,"ty":4,"nm":"Splash 3","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-262},"p":{"a":0,"k":[112,11.66,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":8,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":13,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":15.0000006109625}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":8.00000032584668,"op":17.0000006924242,"st":-13.0000005295009,"bm":0,"sr":1},{"ddd":0,"ind":8,"ty":4,"nm":"Splash 2","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-191},"p":{"a":0,"k":[342,-100.34,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":5,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":7,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":10,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":12.00000048877}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":5.00000020365417,"op":14.0000005702317,"st":-16.0000006516934,"bm":0,"sr":1},{"ddd":0,"ind":9,"ty":4,"nm":"Splash 1","ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":-11},"p":{"a":0,"k":[262,295.66,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":4,"s":[{"i":[[0.066,-0.121],[0.121,0.066],[-0.066,0.121],[-0.121,-0.066]],"o":[[-0.066,0.121],[-0.121,-0.066],[0.066,-0.121],[0.121,0.066]],"v":[[107.47,-230.13],[107.13,-230.03],[107.03,-230.37],[107.37,-230.47]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":6,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[133.035,-254.315],[117.053,-239.365],[124.694,-258.857],[130.88,-260.246]],"c":true}],"e":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":9,"s":[{"i":[[1.254,-2.303],[0.675,0.552],[-1.254,2.303],[-2.303,-1.254]],"o":[[-1.254,2.303],[-0.675,-0.552],[1.254,-2.303],[2.303,1.254]],"v":[[135.535,-259.315],[129.053,-258.115],[127.194,-263.857],[133.38,-265.246]],"c":true}],"e":[{"i":[[0.098,-0.179],[0.053,0.043],[-0.098,0.179],[-0.179,-0.098]],"o":[[-0.098,0.179],[-0.053,-0.043],[0.098,-0.179],[0.179,0.098]],"v":[[136.689,-271.566],[136.185,-271.473],[136.04,-271.919],[136.521,-272.027]],"c":true}]},{"t":11.0000004480392}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":4.00000016292334,"op":13.0000005295009,"st":-17.0000006924242,"bm":0,"sr":1},{"ddd":0,"ind":10,"ty":4,"nm":"fleck 5","parent":13,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":7},"p":{"a":0,"k":[-1.5,-24.84,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[{"i":[[0,-0.207],[0.207,0],[0,0.207],[-0.207,0]],"o":[[0,0.207],[-0.207,0],[0,-0.207],[0.207,0]],"v":[[-202.125,0],[-202.5,0.375],[-202.875,0],[-202.5,-0.375]],"c":true}],"e":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,5.156],[-199.844,7.375],[-202.062,5.156],[-199.844,2.937]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":33,"s":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,5.156],[-199.844,7.375],[-202.062,5.156],[-199.844,2.937]],"c":true}],"e":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,25.156],[-199.844,27.414],[-202.062,25.156],[-199.937,9.187]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":38,"s":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,25.156],[-199.844,27.414],[-202.062,25.156],[-199.937,9.187]],"c":true}],"e":[{"i":[[-1.25,-4.156],[1.225,0],[0.031,1.225],[-0.75,-0.406]],"o":[[0.353,1.173],[-1.225,0],[-0.125,-4.969],[0.855,0.519]],"v":[[-197.625,42.656],[-199.844,44.914],[-202.062,42.656],[-199.937,26.687]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":39,"s":[{"i":[[-1.25,-4.156],[1.225,0],[0.031,1.225],[-0.75,-0.406]],"o":[[0.353,1.173],[-1.225,0],[-0.125,-4.969],[0.855,0.519]],"v":[[-197.625,42.656],[-199.844,44.914],[-202.062,42.656],[-199.937,26.687]],"c":true}],"e":[{"i":[[-2.175,-3.756],[1.192,-0.283],[0.313,1.185],[-0.824,-0.222]],"o":[[0.614,1.06],[-1.192,0.283],[-1.268,-4.806],[0.952,0.308]],"v":[[-191.053,64.48],[-192.691,67.189],[-195.371,65.504],[-196.988,49.476]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":41,"s":[{"i":[[-2.175,-3.756],[1.192,-0.283],[0.313,1.185],[-0.824,-0.222]],"o":[[0.614,1.06],[-1.192,0.283],[-1.268,-4.806],[0.952,0.308]],"v":[[-191.053,64.48],[-192.691,67.189],[-195.371,65.504],[-196.988,49.476]],"c":true}],"e":[{"i":[[-0.416,-1.152],[1.153,-0.416],[0.416,1.153],[-1.153,0.416]],"o":[[0.416,1.152],[-1.153,0.416],[-0.416,-1.153],[1.153,-0.416]],"v":[[-179.68,88.246],[-181.001,91.123],[-183.854,89.752],[-187.275,74.01]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":43,"s":[{"i":[[-0.416,-1.152],[1.153,-0.416],[0.416,1.153],[-1.153,0.416]],"o":[[0.416,1.152],[-1.153,0.416],[-0.416,-1.153],[1.153,-0.416]],"v":[[-179.68,88.246],[-181.001,91.123],[-183.854,89.752],[-187.275,74.01]],"c":true}],"e":[{"i":[[-0.51,-1.114],[1.114,-0.51],[0.51,1.114],[-1.114,0.51]],"o":[[0.51,1.114],[-1.114,0.51],[-0.51,-1.114],[1.114,-0.51]],"v":[[-177.826,91.483],[-178.921,94.424],[-181.861,93.329],[-180.767,90.389]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":45,"s":[{"i":[[-0.51,-1.114],[1.114,-0.51],[0.51,1.114],[-1.114,0.51]],"o":[[0.51,1.114],[-1.114,0.51],[-0.51,-1.114],[1.114,-0.51]],"v":[[-177.826,91.483],[-178.921,94.424],[-181.861,93.329],[-180.767,90.389]],"c":true}],"e":[{"i":[[-0.082,-0.179],[0.179,-0.082],[0.082,0.179],[-0.179,0.082]],"o":[[0.082,0.179],[-0.179,0.082],[-0.082,-0.179],[0.179,-0.082]],"v":[[-179.519,92.258],[-179.695,92.73],[-180.168,92.555],[-179.992,92.082]],"c":true}]},{"t":47.0000019143492}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":31.0000012626559,"op":48.0000019550801,"st":10.0000004073083,"bm":0,"sr":1},{"ddd":0,"ind":11,"ty":4,"nm":"fleck 4","parent":13,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":14},"p":{"a":0,"k":[-25.487,-18.198,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":24,"s":[{"i":[[0,-0.207],[0.207,0],[0,0.207],[-0.207,0]],"o":[[0,0.207],[-0.207,0],[0,-0.207],[0.207,0]],"v":[[-202.125,0],[-202.5,0.375],[-202.875,0],[-202.5,-0.375]],"c":true}],"e":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,5.156],[-199.844,7.375],[-202.062,5.156],[-199.844,2.937]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":26,"s":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,5.156],[-199.844,7.375],[-202.062,5.156],[-199.844,2.937]],"c":true}],"e":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,25.156],[-199.844,27.414],[-202.062,25.156],[-199.937,9.187]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,25.156],[-199.844,27.414],[-202.062,25.156],[-199.937,9.187]],"c":true}],"e":[{"i":[[-1.25,-4.156],[1.225,0],[0.031,1.225],[-0.75,-0.406]],"o":[[0.353,1.173],[-1.225,0],[-0.125,-4.969],[0.855,0.519]],"v":[[-197.625,42.656],[-199.844,44.914],[-202.062,42.656],[-199.937,26.687]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":32,"s":[{"i":[[-1.25,-4.156],[1.225,0],[0.031,1.225],[-0.75,-0.406]],"o":[[0.353,1.173],[-1.225,0],[-0.125,-4.969],[0.855,0.519]],"v":[[-197.625,42.656],[-199.844,44.914],[-202.062,42.656],[-199.937,26.687]],"c":true}],"e":[{"i":[[-2.175,-3.756],[1.192,-0.283],[0.313,1.185],[-0.824,-0.222]],"o":[[0.614,1.06],[-1.192,0.283],[-1.268,-4.806],[0.952,0.308]],"v":[[-191.053,64.48],[-192.691,67.189],[-195.371,65.504],[-196.988,49.476]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":34,"s":[{"i":[[-2.175,-3.756],[1.192,-0.283],[0.313,1.185],[-0.824,-0.222]],"o":[[0.614,1.06],[-1.192,0.283],[-1.268,-4.806],[0.952,0.308]],"v":[[-191.053,64.48],[-192.691,67.189],[-195.371,65.504],[-196.988,49.476]],"c":true}],"e":[{"i":[[-0.416,-1.152],[1.153,-0.416],[0.416,1.153],[-1.153,0.416]],"o":[[0.416,1.152],[-1.153,0.416],[-0.416,-1.153],[1.153,-0.416]],"v":[[-179.68,88.246],[-181.001,91.123],[-183.854,89.752],[-187.275,74.01]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":36,"s":[{"i":[[-0.416,-1.152],[1.153,-0.416],[0.416,1.153],[-1.153,0.416]],"o":[[0.416,1.152],[-1.153,0.416],[-0.416,-1.153],[1.153,-0.416]],"v":[[-179.68,88.246],[-181.001,91.123],[-183.854,89.752],[-187.275,74.01]],"c":true}],"e":[{"i":[[-0.51,-1.114],[1.114,-0.51],[0.51,1.114],[-1.114,0.51]],"o":[[0.51,1.114],[-1.114,0.51],[-0.51,-1.114],[1.114,-0.51]],"v":[[-177.826,91.483],[-178.921,94.424],[-181.861,93.329],[-180.767,90.389]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":38,"s":[{"i":[[-0.51,-1.114],[1.114,-0.51],[0.51,1.114],[-1.114,0.51]],"o":[[0.51,1.114],[-1.114,0.51],[-0.51,-1.114],[1.114,-0.51]],"v":[[-177.826,91.483],[-178.921,94.424],[-181.861,93.329],[-180.767,90.389]],"c":true}],"e":[{"i":[[-0.082,-0.179],[0.179,-0.082],[0.082,0.179],[-0.179,0.082]],"o":[[0.082,0.179],[-0.179,0.082],[-0.082,-0.179],[0.179,-0.082]],"v":[[-179.519,92.258],[-179.695,92.73],[-180.168,92.555],[-179.992,92.082]],"c":true}]},{"t":40.0000016292334}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":24.00000097754,"op":41.0000016699642,"st":3.00000012219251,"bm":0,"sr":1},{"ddd":0,"ind":12,"ty":4,"nm":"fleck 1","parent":13,"ks":{"o":{"a":0,"k":100},"r":{"a":0,"k":0},"p":{"a":0,"k":[3.784,-8.842,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"st","c":{"a":0,"k":[0.917647,0.411765,0.05098,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":0},"lc":1,"lj":1,"ml":4,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"ix":1,"mn":"ADBE Vector Group"},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":21,"s":[{"i":[[0,-0.207],[0.207,0],[0,0.207],[-0.207,0]],"o":[[0,0.207],[-0.207,0],[0,-0.207],[0.207,0]],"v":[[-197.125,0],[-197.5,0.375],[-197.875,0],[-197.5,-0.375]],"c":true}],"e":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,5.156],[-199.844,7.375],[-202.062,5.156],[-199.844,2.937]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":23,"s":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,5.156],[-199.844,7.375],[-202.062,5.156],[-199.844,2.937]],"c":true}],"e":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,25.156],[-199.844,27.414],[-202.062,25.156],[-199.937,9.187]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":28,"s":[{"i":[[0,-1.225],[1.225,0],[0,1.225],[-1.225,0]],"o":[[0,1.225],[-1.225,0],[0,-1.225],[1.225,0]],"v":[[-197.625,25.156],[-199.844,27.414],[-202.062,25.156],[-199.937,9.187]],"c":true}],"e":[{"i":[[-1.25,-4.156],[1.225,0],[0.031,1.225],[-0.75,-0.406]],"o":[[0.353,1.173],[-1.225,0],[-0.125,-4.969],[0.855,0.519]],"v":[[-197.625,42.656],[-199.844,44.914],[-202.062,42.656],[-199.937,26.687]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":29,"s":[{"i":[[-1.25,-4.156],[1.225,0],[0.031,1.225],[-0.75,-0.406]],"o":[[0.353,1.173],[-1.225,0],[-0.125,-4.969],[0.855,0.519]],"v":[[-197.625,42.656],[-199.844,44.914],[-202.062,42.656],[-199.937,26.687]],"c":true}],"e":[{"i":[[-2.175,-3.756],[1.192,-0.283],[0.313,1.185],[-0.824,-0.222]],"o":[[0.614,1.06],[-1.192,0.283],[-1.268,-4.806],[0.952,0.308]],"v":[[-191.053,64.48],[-192.691,67.189],[-195.371,65.504],[-196.988,49.476]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":31,"s":[{"i":[[-2.175,-3.756],[1.192,-0.283],[0.313,1.185],[-0.824,-0.222]],"o":[[0.614,1.06],[-1.192,0.283],[-1.268,-4.806],[0.952,0.308]],"v":[[-191.053,64.48],[-192.691,67.189],[-195.371,65.504],[-196.988,49.476]],"c":true}],"e":[{"i":[[-0.416,-1.152],[1.153,-0.416],[0.416,1.153],[-1.153,0.416]],"o":[[0.416,1.152],[-1.153,0.416],[-0.416,-1.153],[1.153,-0.416]],"v":[[-179.68,88.246],[-181.001,91.123],[-183.854,89.752],[-187.275,74.01]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":33,"s":[{"i":[[-0.416,-1.152],[1.153,-0.416],[0.416,1.153],[-1.153,0.416]],"o":[[0.416,1.152],[-1.153,0.416],[-0.416,-1.153],[1.153,-0.416]],"v":[[-179.68,88.246],[-181.001,91.123],[-183.854,89.752],[-187.275,74.01]],"c":true}],"e":[{"i":[[-0.51,-1.114],[1.114,-0.51],[0.51,1.114],[-1.114,0.51]],"o":[[0.51,1.114],[-1.114,0.51],[-0.51,-1.114],[1.114,-0.51]],"v":[[-177.826,91.483],[-178.921,94.424],[-181.861,93.329],[-180.767,90.389]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"n":"0p833_0p833_0p167_0p167","t":35,"s":[{"i":[[-0.51,-1.114],[1.114,-0.51],[0.51,1.114],[-1.114,0.51]],"o":[[0.51,1.114],[-1.114,0.51],[-0.51,-1.114],[1.114,-0.51]],"v":[[-177.826,91.483],[-178.921,94.424],[-181.861,93.329],[-180.767,90.389]],"c":true}],"e":[{"i":[[-0.082,-0.179],[0.179,-0.082],[0.082,0.179],[-0.179,0.082]],"o":[[0.082,0.179],[-0.179,0.082],[-0.082,-0.179],[0.179,-0.082]],"v":[[-179.519,92.258],[-179.695,92.73],[-180.168,92.555],[-179.992,92.082]],"c":true}]},{"t":37.0000015070409}]},"nm":"Path 1","mn":"ADBE Vector Shape - Group"},{"ty":"fl","c":{"a":0,"k":[0.8470588,0.0862745,0.2117647,1]},"o":{"a":0,"k":100},"r":1,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill"}],"ip":21.0000008553475,"op":38.0000015477717,"st":0,"bm":0,"sr":1},{"ddd":0,"ind":13,"ty":3,"nm":"Shape Layer 1","ks":{"o":{"a":0,"k":0},"r":{"a":1,"k":[{"i":{"x":[0.497],"y":[1]},"o":{"x":[0.397],"y":[0]},"n":["0p497_1_0p397_0"],"t":9,"s":[0],"e":[360]},{"t":43.0000017514259}]},"p":{"a":0,"k":[295.5,291.5,0]},"a":{"a":0,"k":[0,0,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"ip":0,"op":67.0000027289659,"st":0,"bm":0,"sr":1}]}
--------------------------------------------------------------------------------