├── .gitignore ├── COPYING.txt ├── LICENSE.txt ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── softbankrobotics │ │ └── qisdktutorials │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── hello-en.top │ │ ├── hello-ja.top │ │ └── robot │ │ │ └── robotsdk.xml │ ├── ic_app_icon-web.png │ ├── java │ │ └── com │ │ │ └── softbankrobotics │ │ │ └── qisdktutorials │ │ │ ├── model │ │ │ ├── data │ │ │ │ ├── Tutorial.kt │ │ │ │ ├── TutorialCategory.kt │ │ │ │ ├── TutorialId.kt │ │ │ │ └── TutorialLevel.kt │ │ │ └── repository │ │ │ │ └── TutorialRepository.kt │ │ │ ├── ui │ │ │ ├── bilateralswitch │ │ │ │ ├── BilateralSwitch.kt │ │ │ │ ├── OnCheckedChangeListener.java │ │ │ │ └── RoundedLayout.kt │ │ │ ├── categories │ │ │ │ ├── CategoriesActivity.kt │ │ │ │ ├── CategoriesContract.kt │ │ │ │ ├── CategoriesPresenter.kt │ │ │ │ ├── CategoriesRobot.kt │ │ │ │ ├── CategoriesRouter.kt │ │ │ │ ├── OnTutorialClickedListener.kt │ │ │ │ ├── TutorialAdapter.kt │ │ │ │ └── TutorialViewHolder.kt │ │ │ ├── conversation │ │ │ │ ├── ConversationAdapter.kt │ │ │ │ ├── ConversationBinder.kt │ │ │ │ ├── ConversationItem.kt │ │ │ │ ├── ConversationItemType.kt │ │ │ │ ├── ConversationView.kt │ │ │ │ └── ConversationViewHolder.kt │ │ │ ├── splashscreen │ │ │ │ └── SplashScreenActivity.kt │ │ │ ├── tutorials │ │ │ │ ├── TutorialActivity.kt │ │ │ │ ├── autonomousabilities │ │ │ │ │ └── AutonomousAbilitiesTutorialActivity.kt │ │ │ │ ├── conversation │ │ │ │ │ ├── bookmarks │ │ │ │ │ │ └── BookmarksTutorialActivity.kt │ │ │ │ │ ├── chatlocale │ │ │ │ │ │ └── ChatLocaleTutorialActivity.kt │ │ │ │ │ ├── dynamicconcepts │ │ │ │ │ │ ├── DynamicConceptsTutorialActivity.kt │ │ │ │ │ │ ├── GreetingAdapter.kt │ │ │ │ │ │ ├── GreetingViewHolder.kt │ │ │ │ │ │ └── OnGreetingRemovedListener.kt │ │ │ │ │ ├── execute │ │ │ │ │ │ └── ExecuteTutorialActivity.kt │ │ │ │ │ ├── listen │ │ │ │ │ │ └── ListenTutorialActivity.kt │ │ │ │ │ ├── qichatbot │ │ │ │ │ │ └── QiChatbotTutorialActivity.kt │ │ │ │ │ └── qichatvariables │ │ │ │ │ │ └── QiChatVariablesTutorialActivity.kt │ │ │ │ ├── gettingstarted │ │ │ │ │ └── HelloHumanTutorialActivity.kt │ │ │ │ ├── motion │ │ │ │ │ ├── animate │ │ │ │ │ │ └── AnimateTutorialActivity.kt │ │ │ │ │ ├── animationlabels │ │ │ │ │ │ └── AnimationLabelActivity.kt │ │ │ │ │ ├── attachedframes │ │ │ │ │ │ └── FollowHumanTutorialActivity.kt │ │ │ │ │ ├── enforcetabletreachability │ │ │ │ │ │ └── EnforceTabletReachabilityTutorialActivity.kt │ │ │ │ │ ├── extendmap │ │ │ │ │ │ └── MapExtensionTutorialActivity.kt │ │ │ │ │ ├── freeframes │ │ │ │ │ │ └── GoToWorldTutorialActivity.kt │ │ │ │ │ ├── gotoframe │ │ │ │ │ │ └── GoToTutorialActivity.kt │ │ │ │ │ ├── lookat │ │ │ │ │ │ └── LookAtTutorialActivity.kt │ │ │ │ │ └── trajectory │ │ │ │ │ │ └── TrajectoryTutorialActivity.kt │ │ │ │ └── perceptions │ │ │ │ │ ├── detecthumanswithlocalization │ │ │ │ │ └── DetectHumansWithLocalizationTutorialActivity.kt │ │ │ │ │ ├── emotiondetection │ │ │ │ │ ├── BasicEmotion.kt │ │ │ │ │ ├── BasicEmotionObserver.kt │ │ │ │ │ ├── EmotionTutorialActivity.kt │ │ │ │ │ └── OnBasicEmotionChangedListener.kt │ │ │ │ │ ├── humanawareness │ │ │ │ │ ├── HumanInfo.kt │ │ │ │ │ ├── HumanInfoAdapter.kt │ │ │ │ │ ├── HumanInfoViewHolder.kt │ │ │ │ │ └── PeopleCharacteristicsTutorialActivity.kt │ │ │ │ │ ├── takepicture │ │ │ │ │ └── TakePictureTutorialActivity.kt │ │ │ │ │ └── touch │ │ │ │ │ └── TouchTutorialActivity.kt │ │ │ └── tutorialtoolbar │ │ │ │ └── TutorialToolbar.kt │ │ │ └── utils │ │ │ ├── Constants.kt │ │ │ └── KeyboardUtils.kt │ └── res │ │ ├── color │ │ ├── button_text_color_selector.xml │ │ └── navigation_tint_selector.xml │ │ ├── drawable │ │ ├── advanced_level_shape.xml │ │ ├── basic_level_shape.xml │ │ ├── button_background_selector.xml │ │ ├── button_shape_disabled.xml │ │ ├── button_shape_pressed.xml │ │ ├── button_shape_selected.xml │ │ ├── button_shape_unselected.xml │ │ ├── category_selector.xml │ │ ├── empty_divider_big.xml │ │ ├── empty_divider_tutorials.xml │ │ ├── ic_add.xml │ │ ├── ic_baseline_arrow_back.xml │ │ ├── ic_baseline_close.xml │ │ ├── ic_brains.xml │ │ ├── ic_check.xml │ │ ├── ic_delete.xml │ │ ├── ic_icons_cute_anon_anger.xml │ │ ├── ic_icons_cute_anon_joyful.xml │ │ ├── ic_icons_cute_anon_neutral.xml │ │ ├── ic_icons_cute_anon_sad.xml │ │ ├── ic_icons_cute_anon_smile.xml │ │ ├── ic_icons_cute_anon_unknown.xml │ │ ├── ic_img_icon_humanmen.xml │ │ ├── ic_img_icon_pepper.xml │ │ ├── ic_move.xml │ │ ├── ic_talk.xml │ │ ├── navigation_background_selector.xml │ │ ├── sbr_logo.png │ │ └── switch_level_shape.xml │ │ ├── font │ │ ├── open_sans_bold.ttf │ │ ├── open_sans_light_italic.ttf │ │ └── open_sans_semibold.ttf │ │ ├── layout │ │ ├── activity_autonomous_abilities_tutorial.xml │ │ ├── activity_categories.xml │ │ ├── activity_chat_locale_tutorial.xml │ │ ├── activity_detect_humans_with_localization_tutorial.xml │ │ ├── activity_dynamic_concepts_tutorial.xml │ │ ├── activity_emotion_tutorial.xml │ │ ├── activity_enforce_tablet_reachability_tutorial.xml │ │ ├── activity_exploration_map_representation_tutorial.xml │ │ ├── activity_follow_human_tutorial.xml │ │ ├── activity_go_to_world_tutorial.xml │ │ ├── activity_look_at_tutorial.xml │ │ ├── activity_people_characteristics_tutorial.xml │ │ ├── activity_qi_chat_variables_tutorial.xml │ │ ├── activity_splash_screen.xml │ │ ├── activity_take_picture_tutorial.xml │ │ ├── bilateral_switch.xml │ │ ├── conversation_layout.xml │ │ ├── greeting_layout.xml │ │ ├── human_info_layout.xml │ │ ├── layout_error_log_view.xml │ │ ├── layout_human_input_view.xml │ │ ├── layout_info_log_view.xml │ │ ├── layout_robot_output_view.xml │ │ ├── tutorial_layout.xml │ │ └── tutorial_toolbar.xml │ │ ├── mipmap-hdpi │ │ └── ic_app_icon.png │ │ ├── mipmap-mdpi │ │ └── ic_app_icon.png │ │ ├── mipmap-xhdpi │ │ └── ic_app_icon.png │ │ ├── mipmap-xxhdpi │ │ └── ic_app_icon.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_app_icon.png │ │ ├── raw │ │ ├── common.top │ │ ├── dance.pmt │ │ ├── dance_b001.qianim │ │ ├── dog_a001.qianim │ │ ├── dog_sound.ogg │ │ ├── elephant_a001.qianim │ │ ├── elephant_sound.ogg │ │ ├── execute.top │ │ ├── greetings.top │ │ ├── greetings_dynamic.top │ │ ├── mimic_animal.top │ │ ├── move_tutorials.top │ │ ├── raise_both_hands_b001.qianim │ │ ├── smart_tutorials.top │ │ ├── talk_tutorials.top │ │ └── variable.top │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── attrs_bilateral_switch.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── plurals.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── softbankrobotics │ └── qisdktutorials │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | ### JetBrains template 11 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 12 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 13 | 14 | # User-specific stuff: 15 | .idea 16 | 17 | # Sensitive or high-churn files: 18 | .idea/dataSources/ 19 | .idea/dataSources.ids 20 | .idea/dataSources.xml 21 | .idea/dataSources.local.xml 22 | .idea/sqlDataSources.xml 23 | .idea/dynamic.xml 24 | .idea/uiDesigner.xml 25 | 26 | # Gradle: 27 | .idea/gradle.xml 28 | .idea/libraries 29 | 30 | # Mongo Explorer plugin: 31 | .idea/mongoSettings.xml 32 | 33 | ## File-based project format: 34 | *.iws 35 | 36 | ## Plugin-specific files: 37 | 38 | # IntelliJ 39 | /out/ 40 | 41 | # mpeltonen/sbt-idea plugin 42 | .idea_modules/ 43 | 44 | # JIRA plugin 45 | atlassian-ide-plugin.xml 46 | 47 | # Crashlytics plugin (for Android Studio and IntelliJ) 48 | com_crashlytics_export_strings.xml 49 | crashlytics.properties 50 | crashlytics-build.properties 51 | fabric.properties 52 | ### Java template 53 | *.class 54 | 55 | # BlueJ files 56 | *.ctxt 57 | 58 | # Mobile Tools for Java (J2ME) 59 | .mtj.tmp/ 60 | 61 | # Package Files # 62 | *.jar 63 | *.war 64 | *.ear 65 | 66 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 67 | hs_err_pid* 68 | ### Android template 69 | # Built application files 70 | *.apk 71 | *.ap_ 72 | 73 | # Files for the ART/Dalvik VM 74 | *.dex 75 | 76 | # Java class files 77 | *.class 78 | 79 | # Generated files 80 | bin/ 81 | gen/ 82 | out/ 83 | 84 | # Gradle files 85 | .gradle/ 86 | build/ 87 | 88 | # Local configuration file (sdk path, etc) 89 | local.properties 90 | 91 | # Proguard folder generated by Eclipse 92 | proguard/ 93 | 94 | # Log Files 95 | *.log 96 | 97 | # Android Studio Navigation editor temp files 98 | .navigation/ 99 | 100 | # Android Studio captures folder 101 | captures/ 102 | 103 | # Intellij 104 | *.iml 105 | .idea/workspace.xml 106 | .idea/tasks.xml 107 | .idea/libraries 108 | 109 | # Keystore files 110 | *.jks 111 | 112 | # External native build folder generated in Android Studio 2.2 and later 113 | .externalNativeBuild 114 | ### Gradle template 115 | .gradle 116 | /build/ 117 | 118 | # Ignore Gradle GUI config 119 | gradle-app.setting 120 | 121 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 122 | !gradle-wrapper.jar 123 | 124 | # Cache of project 125 | .gradletasknamecache 126 | 127 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 128 | # gradle/wrapper/gradle-wrapper.properties 129 | 130 | # idea misc 131 | .idea/misc.xml 132 | 133 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2018, Softbank Robotics Europe 3 | All rights reserved. 4 | 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | * Neither the name of the Softbank Robotics nor the 14 | names of its contributors may be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL Softbank Robotics BE LIABLE FOR ANY 22 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, SoftBank Robotics Europe SAS 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 met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the SoftBank Robotics Europe SAS nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL SoftBank Robotics Europe SAS BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QiSDK Tutorials 2 | 3 | **QiSDK Tutorials** is an Android application for Pepper the robot. 4 | It was developed using the QiSDK (https://qisdk.softbankrobotics.com). 5 | 6 | This application provides an easy access to the tutorial sample codes. 7 | 8 | Any Android developer wanting to create an 9 | application for Pepper should go through these tutorials. 10 | 11 | They cover Pepper main functionalities and show both the basic and 12 | advanced tools provided by QiSDK. 13 | 14 | ## Minimum configuration 15 | 16 | * Pepper 1.9. 17 | * API level 3. 18 | 19 | ## Additional resources 20 | 21 | A step-by-step guide for these tutorials is available 22 | in the official [Pepper SDK for Android site](https://qisdk.softbankrobotics.com). 23 | 24 | ## License 25 | 26 | See the [COPYING](COPYING) file for the license. 27 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-android-extensions' 4 | 5 | android { 6 | compileSdkVersion 29 7 | buildToolsVersion '29.0.3' 8 | defaultConfig { 9 | applicationId "com.softbankrobotics.qisdktutorials" 10 | minSdkVersion 23 11 | targetSdkVersion 29 12 | versionCode VERSION_CODE.toInteger() 13 | versionName VERSION_NAME 14 | testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | compileOptions { 23 | sourceCompatibility JavaVersion.VERSION_1_8 24 | targetCompatibility JavaVersion.VERSION_1_8 25 | } 26 | } 27 | 28 | dependencies { 29 | // local libs 30 | implementation fileTree(include: ['*.jar'], dir: 'libs') 31 | // support 32 | implementation "androidx.appcompat:appcompat:$androidx_version" 33 | implementation "androidx.recyclerview:recyclerview:$androidx_version" 34 | implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version" 35 | // tests 36 | testImplementation 'junit:junit:4.12' 37 | androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { 38 | exclude group: 'com.android.support', module: 'support-annotations' 39 | }) 40 | // Pepper 41 | implementation "com.aldebaran:qisdk:$qisdk_version" 42 | implementation "com.aldebaran:qisdk-design:$qisdk_version" 43 | // Kotlin 44 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 45 | } 46 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/adrien.kvaternik/Android/Sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/softbankrobotics/qisdktutorials/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.softbankrobotics.qisdktutorials; 2 | 3 | import android.content.Context; 4 | import androidx.test.platform.app.InstrumentationRegistry; 5 | import androidx.test.ext.junit.runners.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.softbankrobotics.qisdktutorial", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /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 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/assets/hello-en.top: -------------------------------------------------------------------------------- 1 | topic: ~hello() 2 | 3 | proposal: %start Say hello to start the discussion. 4 | 5 | u:(hello) hello 6 | -------------------------------------------------------------------------------- /app/src/main/assets/hello-ja.top: -------------------------------------------------------------------------------- 1 | topic: ~hello() 2 | 3 | proposal: %start 会話を始めるためには、スタート、と言ってください! 4 | 5 | u:(こんにちは) こんにちは 6 | -------------------------------------------------------------------------------- /app/src/main/assets/robot/robotsdk.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/ic_app_icon-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldebaran/qisdk-tutorials/5f8839a018516982d8672814bbd77e05fe44796b/app/src/main/ic_app_icon-web.png -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/model/data/Tutorial.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.model.data 7 | 8 | import androidx.annotation.StringRes 9 | 10 | /** 11 | * Represents a tutorial. 12 | */ 13 | data class Tutorial(val id: TutorialId, @param:StringRes @field:StringRes @get:StringRes val nameResId: Int, 14 | val qiChatbotId: String, val tutorialLevel: TutorialLevel) { 15 | var isSelected: Boolean = false 16 | var isEnabled: Boolean = true 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/model/data/TutorialCategory.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.model.data 7 | 8 | /** 9 | * Represents a tutorial category. 10 | */ 11 | enum class TutorialCategory { 12 | TALK, 13 | MOVE, 14 | SMART 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/model/data/TutorialId.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.model.data 7 | 8 | /** 9 | * Represents a tutorial identifier. 10 | */ 11 | enum class TutorialId { 12 | SAY, 13 | QICHATBOT, 14 | LISTEN, 15 | ANIMATION, 16 | GOTO, 17 | LOOKAT, 18 | CHARACTERISTICS, 19 | TOUCH, 20 | BOOKMARK, 21 | EXECUTE, 22 | DYNAMIC_CONCEPT, 23 | QICHAT_VARIABLE, 24 | GOTO_WORLD, 25 | ATTACHED_FRAME, 26 | AUTONOMOUS_ABILITIES, 27 | TRAJECTORY, 28 | EMOTION, 29 | ENFORCE_TABLET_REACHABILITY, 30 | TAKE_PICTURE, 31 | ANIMATION_LABEL, 32 | DETECT_HUMANS_WITH_LOCALIZATION, 33 | CHAT_LOCALE, 34 | EXTEND_MAP 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/model/data/TutorialLevel.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.model.data 7 | 8 | /** 9 | * Represents a tutorial level. 10 | */ 11 | enum class TutorialLevel { 12 | BASIC, 13 | ADVANCED 14 | } 15 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/bilateralswitch/OnCheckedChangeListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.bilateralswitch; 7 | 8 | 9 | public interface OnCheckedChangeListener { 10 | void onCheckedChanged(boolean isChecked); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/bilateralswitch/RoundedLayout.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.bilateralswitch 7 | 8 | import android.content.Context 9 | import android.graphics.Bitmap 10 | import android.graphics.Canvas 11 | import android.graphics.Color 12 | import android.graphics.Paint 13 | import android.graphics.PorterDuff 14 | import android.graphics.PorterDuffXfermode 15 | import android.graphics.RectF 16 | import android.util.AttributeSet 17 | import android.util.TypedValue 18 | import android.widget.FrameLayout 19 | 20 | private const val CORNER_RADIUS = 42.0f 21 | 22 | class RoundedLayout(context: Context, attrs: AttributeSet?, defStyle: Int) : FrameLayout(context, attrs, defStyle) { 23 | 24 | private lateinit var paint: Paint 25 | private lateinit var maskPaint: Paint 26 | private var cornerRadius: Float = 0f 27 | 28 | init { 29 | init(context) 30 | } 31 | 32 | constructor(context: Context): this(context, null) 33 | constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0) 34 | 35 | private fun init(context: Context) { 36 | val metrics = context.resources.displayMetrics 37 | cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, CORNER_RADIUS, metrics) 38 | 39 | paint = Paint(Paint.ANTI_ALIAS_FLAG) 40 | 41 | maskPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) 42 | maskPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) 43 | 44 | setWillNotDraw(false) 45 | } 46 | 47 | override fun draw(canvas: Canvas) { 48 | val offscreenBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) 49 | val offscreenCanvas = Canvas(offscreenBitmap) 50 | 51 | super.draw(offscreenCanvas) 52 | 53 | val mask = createMask(width, height) 54 | 55 | offscreenCanvas.drawBitmap(mask, 0f, 0f, maskPaint) 56 | canvas.drawBitmap(offscreenBitmap, 0f, 0f, paint) 57 | } 58 | 59 | private fun createMask(width: Int, height: Int): Bitmap { 60 | val mask = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8) 61 | val canvas = Canvas(mask) 62 | 63 | val paint = Paint(Paint.ANTI_ALIAS_FLAG) 64 | paint.color = Color.WHITE 65 | 66 | canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint) 67 | 68 | paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) 69 | canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), cornerRadius, cornerRadius, paint) 70 | 71 | return mask 72 | } 73 | } -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/categories/CategoriesContract.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.categories 7 | 8 | import android.content.Context 9 | 10 | import com.softbankrobotics.qisdktutorials.model.data.Tutorial 11 | import com.softbankrobotics.qisdktutorials.model.data.TutorialCategory 12 | import com.softbankrobotics.qisdktutorials.model.data.TutorialLevel 13 | 14 | /** 15 | * Contract for the categories. 16 | */ 17 | internal interface CategoriesContract { 18 | 19 | interface View { 20 | fun showTutorials(tutorials: List) 21 | fun selectTutorial(tutorial: Tutorial) 22 | fun goToTutorial(tutorial: Tutorial) 23 | fun selectCategory(category: TutorialCategory) 24 | fun selectLevel(level: TutorialLevel) 25 | } 26 | 27 | interface Presenter { 28 | fun bind(view: View) 29 | fun unbind() 30 | fun loadTutorials(category: TutorialCategory) 31 | fun loadTutorials(level: TutorialLevel) 32 | fun goToTutorialForQiChatbotId(tutorialQiChatbotId: String) 33 | fun goToTutorial(tutorial: Tutorial) 34 | } 35 | 36 | interface Robot { 37 | fun register(activity: CategoriesActivity) 38 | fun unregister(activity: CategoriesActivity) 39 | fun stopDiscussion(tutorial: Tutorial) 40 | fun selectTopic(category: TutorialCategory) 41 | fun selectLevel(level: TutorialLevel) 42 | } 43 | 44 | interface Router { 45 | fun goToTutorial(tutorial: Tutorial, context: Context) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/categories/CategoriesPresenter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.categories 7 | 8 | import com.softbankrobotics.qisdktutorials.model.data.Tutorial 9 | import com.softbankrobotics.qisdktutorials.model.data.TutorialCategory 10 | import com.softbankrobotics.qisdktutorials.model.data.TutorialLevel 11 | import com.softbankrobotics.qisdktutorials.model.repository.TutorialRepository 12 | 13 | /** 14 | * The presenter for the tutorial categories. 15 | */ 16 | internal class CategoriesPresenter : CategoriesContract.Presenter { 17 | private var view: CategoriesContract.View? = null 18 | private val tutorialRepository: TutorialRepository = TutorialRepository() 19 | private var loadedTutorials = listOf() 20 | private var selectedCategory = TutorialCategory.TALK 21 | private var selectedLevel = TutorialLevel.BASIC 22 | 23 | override fun bind(view: CategoriesContract.View) { 24 | this.view = view 25 | } 26 | 27 | override fun unbind() { 28 | this.view = null 29 | } 30 | 31 | override fun loadTutorials(category: TutorialCategory) { 32 | selectedCategory = category 33 | updateTutorials() 34 | } 35 | 36 | override fun loadTutorials(level: TutorialLevel) { 37 | selectedLevel = level 38 | updateTutorials() 39 | } 40 | 41 | override fun goToTutorialForQiChatbotId(tutorialQiChatbotId: String) { 42 | for (tutorial in loadedTutorials) { 43 | if (tutorial.qiChatbotId == tutorialQiChatbotId) { 44 | view?.selectTutorial(tutorial) 45 | view?.goToTutorial(tutorial) 46 | break 47 | } 48 | } 49 | } 50 | 51 | override fun goToTutorial(tutorial: Tutorial) { 52 | view?.goToTutorial(tutorial) 53 | } 54 | 55 | private fun updateTutorials() { 56 | loadedTutorials = tutorialRepository.getTutorials(selectedCategory, selectedLevel) 57 | view?.selectCategory(selectedCategory) 58 | view?.selectLevel(selectedLevel) 59 | view?.showTutorials(loadedTutorials) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/categories/OnTutorialClickedListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.categories 7 | 8 | import com.softbankrobotics.qisdktutorials.model.data.Tutorial 9 | 10 | /** 11 | * The listener used to handle a click on a tutorial. 12 | */ 13 | internal interface OnTutorialClickedListener { 14 | /** 15 | * Called when a tutorial is clicked. 16 | * @param tutorial the selected tutorial 17 | */ 18 | fun onTutorialClicked(tutorial: Tutorial) 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/categories/TutorialAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.categories 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.LayoutInflater 10 | import android.view.ViewGroup 11 | 12 | import com.softbankrobotics.qisdktutorials.R 13 | import com.softbankrobotics.qisdktutorials.model.data.Tutorial 14 | 15 | /** 16 | * The adapter used to show tutorials. 17 | */ 18 | internal class TutorialAdapter(private val onTutorialClickedListener: OnTutorialClickedListener) : RecyclerView.Adapter() { 19 | 20 | private var tutorials = listOf() 21 | 22 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TutorialViewHolder { 23 | val view = LayoutInflater.from(parent.context).inflate(R.layout.tutorial_layout, parent, false) 24 | return TutorialViewHolder(view, onTutorialClickedListener) 25 | } 26 | 27 | override fun onBindViewHolder(holder: TutorialViewHolder, position: Int) { 28 | val tutorial = tutorials[position] 29 | holder.bind(tutorial) 30 | } 31 | 32 | override fun getItemCount() = tutorials.size 33 | 34 | /** 35 | * Update the tutorials list. 36 | * @param tutorials the tutorials 37 | */ 38 | fun updateTutorials(tutorials: List) { 39 | this.tutorials = tutorials 40 | notifyDataSetChanged() 41 | } 42 | 43 | /** 44 | * Select the specified tutorial. 45 | * @param tutorial the tutorial 46 | */ 47 | fun selectTutorial(tutorial: Tutorial) { 48 | tutorial.isSelected = true 49 | notifyDataSetChanged() 50 | } 51 | 52 | /** 53 | * Unselect all the tutorials. 54 | */ 55 | fun unselectTutorials() { 56 | tutorials.forEach { 57 | it.isSelected = false 58 | } 59 | notifyDataSetChanged() 60 | } 61 | 62 | /** 63 | * Enable / disable all the tutorials. 64 | * @param enabled `true` to enable, `false` to disable 65 | */ 66 | fun setTutorialsEnabled(enabled: Boolean) { 67 | tutorials.forEach { 68 | it.isEnabled = enabled 69 | } 70 | notifyDataSetChanged() 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/categories/TutorialViewHolder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.categories 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.View 10 | 11 | import com.softbankrobotics.qisdktutorials.R 12 | import com.softbankrobotics.qisdktutorials.model.data.Tutorial 13 | import com.softbankrobotics.qisdktutorials.model.data.TutorialLevel 14 | import kotlinx.android.synthetic.main.tutorial_layout.view.* 15 | 16 | /** 17 | * The view holder to show a tutorial. 18 | */ 19 | internal class TutorialViewHolder(itemView: View, private val onTutorialClickedListener: OnTutorialClickedListener) : RecyclerView.ViewHolder(itemView) { 20 | 21 | /** 22 | * Binds a tutorial to the views. 23 | * @param tutorial the tutorial to bind 24 | */ 25 | fun bind(tutorial: Tutorial) { 26 | 27 | with(itemView.radio_button) { 28 | isChecked = tutorial.isSelected 29 | isEnabled = tutorial.isEnabled 30 | text = "\"${itemView.context.getString(tutorial.nameResId)}\"" 31 | setOnClickListener { 32 | onTutorialClickedListener.onTutorialClicked(tutorial) 33 | } 34 | } 35 | 36 | val tutorialLevel = tutorial.tutorialLevel 37 | bindLevelView(tutorialLevel) 38 | } 39 | 40 | /** 41 | * Bind the level view. 42 | * @param tutorialLevel the tutorial level 43 | */ 44 | private fun bindLevelView(tutorialLevel: TutorialLevel) { 45 | when (tutorialLevel) { 46 | TutorialLevel.BASIC -> { 47 | itemView.level_textview.setText(R.string.basic_level) 48 | itemView.level_textview.setBackgroundResource(R.drawable.basic_level_shape) 49 | } 50 | TutorialLevel.ADVANCED -> { 51 | itemView.level_textview.setText(R.string.advanced_level) 52 | itemView.level_textview.setBackgroundResource(R.drawable.advanced_level_shape) 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/conversation/ConversationAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.conversation 7 | 8 | import androidx.annotation.LayoutRes 9 | import androidx.recyclerview.widget.RecyclerView 10 | import android.view.LayoutInflater 11 | import android.view.ViewGroup 12 | 13 | import com.softbankrobotics.qisdktutorials.R 14 | 15 | private const val INFO_LOG_VIEW_TYPE = 0 16 | private const val ERROR_LOG_VIEW_TYPE = 1 17 | private const val ROBOT_OUTPUT_VIEW_TYPE = 2 18 | private const val HUMAN_INPUT_VIEW_TYPE = 3 19 | 20 | /** 21 | * Adapter for the conversation view. 22 | */ 23 | internal class ConversationAdapter : RecyclerView.Adapter() { 24 | 25 | private val items = mutableListOf() 26 | 27 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ConversationViewHolder { 28 | val layout = layoutFromViewType(viewType) 29 | val view = LayoutInflater.from(parent.context).inflate(layout, parent, false) 30 | return ConversationViewHolder(view) 31 | } 32 | 33 | override fun onBindViewHolder(holder: ConversationViewHolder, position: Int) { 34 | val conversationItem = items[position] 35 | holder.bind(conversationItem.text) 36 | } 37 | 38 | override fun getItemCount() = items.size 39 | 40 | override fun getItemViewType(position: Int): Int { 41 | val conversationItem = items[position] 42 | return when (val type = conversationItem.type) { 43 | ConversationItemType.INFO_LOG -> INFO_LOG_VIEW_TYPE 44 | ConversationItemType.ERROR_LOG -> ERROR_LOG_VIEW_TYPE 45 | ConversationItemType.HUMAN_INPUT -> HUMAN_INPUT_VIEW_TYPE 46 | ConversationItemType.ROBOT_OUTPUT -> ROBOT_OUTPUT_VIEW_TYPE 47 | else -> throw IllegalArgumentException("Unknown conversation item type: $type") 48 | } 49 | } 50 | 51 | /** 52 | * Add an item to the view. 53 | * @param text the item text 54 | * @param type the item type 55 | */ 56 | fun addItem(text: String, type: ConversationItemType) { 57 | items.add(ConversationItem(text, type)) 58 | notifyItemInserted(items.size - 1) 59 | } 60 | 61 | @LayoutRes 62 | private fun layoutFromViewType(viewType: Int): Int { 63 | return when (viewType) { 64 | INFO_LOG_VIEW_TYPE -> R.layout.layout_info_log_view 65 | ERROR_LOG_VIEW_TYPE -> R.layout.layout_error_log_view 66 | ROBOT_OUTPUT_VIEW_TYPE -> R.layout.layout_robot_output_view 67 | HUMAN_INPUT_VIEW_TYPE -> R.layout.layout_human_input_view 68 | else -> throw IllegalArgumentException("Unknown view type: $viewType") 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/conversation/ConversationBinder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.conversation 7 | 8 | import android.text.TextUtils 9 | 10 | import com.aldebaran.qi.sdk.`object`.conversation.ConversationStatus 11 | 12 | class ConversationBinder private constructor(private val conversationStatus: ConversationStatus) { 13 | 14 | private var onSayingChangedListener: ConversationStatus.OnSayingChangedListener? = null 15 | private var onHeardListener: ConversationStatus.OnHeardListener? = null 16 | 17 | private fun bind(conversationView: ConversationView) { 18 | onSayingChangedListener = ConversationStatus.OnSayingChangedListener { sayingPhrase -> 19 | val text = sayingPhrase.text 20 | if (!TextUtils.isEmpty(text)) { 21 | conversationView.post { conversationView.addLine(text, ConversationItemType.ROBOT_OUTPUT) } 22 | } 23 | } 24 | 25 | onHeardListener = ConversationStatus.OnHeardListener { 26 | val text = it.text 27 | conversationView.post { conversationView.addLine(text, ConversationItemType.HUMAN_INPUT) } 28 | } 29 | 30 | conversationStatus.addOnSayingChangedListener(onSayingChangedListener) 31 | conversationStatus.addOnHeardListener(onHeardListener) 32 | } 33 | 34 | fun unbind() { 35 | conversationStatus.removeOnSayingChangedListener(onSayingChangedListener) 36 | conversationStatus.removeOnHeardListener(onHeardListener) 37 | onSayingChangedListener = null 38 | onHeardListener = null 39 | } 40 | 41 | companion object { 42 | 43 | internal fun binding(conversationStatus: ConversationStatus, conversationView: ConversationView): ConversationBinder { 44 | return ConversationBinder(conversationStatus).apply { 45 | bind(conversationView) 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/conversation/ConversationItem.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.conversation 7 | 8 | internal class ConversationItem(val text: String, val type: ConversationItemType) 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/conversation/ConversationItemType.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.conversation 7 | 8 | /** 9 | * Represent a conversation item type. 10 | */ 11 | enum class ConversationItemType { 12 | INFO_LOG, 13 | ERROR_LOG, 14 | ROBOT_OUTPUT, 15 | HUMAN_INPUT 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/conversation/ConversationView.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.conversation 7 | 8 | import android.content.Context 9 | import androidx.recyclerview.widget.DividerItemDecoration 10 | import androidx.recyclerview.widget.LinearLayoutManager 11 | import androidx.recyclerview.widget.RecyclerView 12 | import android.util.AttributeSet 13 | 14 | import com.aldebaran.qi.sdk.`object`.conversation.ConversationStatus 15 | import com.softbankrobotics.qisdktutorials.R 16 | 17 | class ConversationView constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : RecyclerView(context, attrs, defStyle) { 18 | 19 | private val adapter = ConversationAdapter() 20 | 21 | init { 22 | setup() 23 | } 24 | 25 | constructor(context: Context, attrs: AttributeSet?): this(context, attrs, 0) 26 | 27 | constructor(context: Context): this(context, null) 28 | 29 | fun bindConversationTo(conversationStatus: ConversationStatus): ConversationBinder = ConversationBinder.binding(conversationStatus, this) 30 | 31 | fun addLine(text: String, type: ConversationItemType) { 32 | adapter.addItem(text, type) 33 | scrollToPosition(adapter.itemCount - 1) 34 | } 35 | 36 | private fun setup() { 37 | layoutManager = LinearLayoutManager(context) 38 | setAdapter(adapter) 39 | 40 | val drawable = context.getDrawable(R.drawable.empty_divider_big) 41 | if (drawable != null) { 42 | val dividerItemDecoration = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) 43 | dividerItemDecoration.setDrawable(drawable) 44 | this.addItemDecoration(dividerItemDecoration) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/conversation/ConversationViewHolder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.conversation 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.View 10 | 11 | import kotlinx.android.synthetic.main.layout_info_log_view.view.* 12 | 13 | /** 14 | * View holder for the conversation view. 15 | */ 16 | internal class ConversationViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 17 | 18 | /** 19 | * Bind the text to the view. 20 | * @param text the text 21 | */ 22 | fun bind(text: String) { 23 | itemView.textview.text = text 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/splashscreen/SplashScreenActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.splashscreen 7 | 8 | import android.content.Intent 9 | import android.os.Bundle 10 | 11 | import com.aldebaran.qi.sdk.design.activity.RobotActivity 12 | import com.aldebaran.qi.sdk.design.activity.conversationstatus.SpeechBarDisplayStrategy 13 | import com.softbankrobotics.qisdktutorials.R 14 | import com.softbankrobotics.qisdktutorials.ui.categories.CategoriesActivity 15 | 16 | import java.util.Timer 17 | import java.util.TimerTask 18 | 19 | /** 20 | * The splashscreen activity. 21 | */ 22 | class SplashScreenActivity : RobotActivity() { 23 | 24 | private var timer: Timer? = null 25 | 26 | override fun onCreate(savedInstanceState: Bundle?) { 27 | super.onCreate(savedInstanceState) 28 | 29 | setSpeechBarDisplayStrategy(SpeechBarDisplayStrategy.OVERLAY) 30 | setContentView(R.layout.activity_splash_screen) 31 | } 32 | 33 | override fun onResume() { 34 | super.onResume() 35 | 36 | timer = Timer() 37 | timer?.schedule(object : TimerTask() { 38 | override fun run() { 39 | goToCategories() 40 | } 41 | }, 1500) 42 | } 43 | 44 | override fun onPause() { 45 | timer?.cancel() 46 | super.onPause() 47 | } 48 | 49 | private fun goToCategories() { 50 | val intent = Intent(this, CategoriesActivity::class.java) 51 | startActivity(intent) 52 | 53 | finish() 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/TutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials 7 | 8 | import android.graphics.Rect 9 | import android.os.Bundle 10 | import androidx.annotation.LayoutRes 11 | import android.view.View 12 | import android.view.ViewTreeObserver 13 | 14 | import com.aldebaran.qi.sdk.design.activity.RobotActivity 15 | import com.softbankrobotics.qisdktutorials.model.data.TutorialLevel 16 | import com.softbankrobotics.qisdktutorials.utils.Constants 17 | import kotlinx.android.synthetic.main.activity_take_picture_tutorial.* 18 | import kotlinx.android.synthetic.main.tutorial_toolbar.* 19 | 20 | /** 21 | * Base class for a tutorial activity. 22 | */ 23 | abstract class TutorialActivity : RobotActivity() { 24 | 25 | private lateinit var rootView: View 26 | private var globalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null 27 | 28 | /** 29 | * Provide the tutorial layout identifier. 30 | * @return The layout identifier. 31 | */ 32 | @get:LayoutRes 33 | protected abstract val layoutId: Int 34 | 35 | override fun onCreate(savedInstanceState: Bundle?) { 36 | super.onCreate(savedInstanceState) 37 | setContentView(layoutId) 38 | setupToolbar() 39 | } 40 | 41 | override fun onResume() { 42 | super.onResume() 43 | 44 | rootView = findViewById(android.R.id.content) 45 | globalLayoutListener = ViewTreeObserver.OnGlobalLayoutListener { 46 | val rect = Rect() 47 | rootView.getWindowVisibleDisplayFrame(rect) 48 | val screenHeight = rootView.height 49 | val keypadHeight = screenHeight.minus(rect.bottom) 50 | 51 | // Hide system UI if keyboard is closed. 52 | if (keypadHeight <= screenHeight * 0.30) { 53 | hideSystemUI() 54 | } 55 | } 56 | rootView.viewTreeObserver?.addOnGlobalLayoutListener(globalLayoutListener) 57 | } 58 | 59 | override fun onPause() { 60 | rootView.viewTreeObserver?.removeOnGlobalLayoutListener(globalLayoutListener) 61 | super.onPause() 62 | } 63 | 64 | /** 65 | * Configures the toolbar. 66 | */ 67 | private fun setupToolbar() { 68 | setSupportActionBar(toolbar) 69 | toolbar.setNavigationOnClickListener { onBackPressed() } 70 | 71 | val nameNotFound = -1 72 | val nameResId = intent.getIntExtra(Constants.Intent.TUTORIAL_NAME_KEY, nameNotFound) 73 | val level = intent.getSerializableExtra(Constants.Intent.TUTORIAL_LEVEL_KEY) as TutorialLevel 74 | if (nameResId != nameNotFound) { 75 | toolbar.setName(nameResId) 76 | toolbar.setLevel(level) 77 | } 78 | 79 | close_button.setOnClickListener { finishAffinity() } 80 | } 81 | 82 | private fun hideSystemUI() { 83 | val decorView = window.decorView 84 | decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 85 | or View.SYSTEM_UI_FLAG_LAYOUT_STABLE 86 | or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 87 | or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 88 | or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 89 | or View.SYSTEM_UI_FLAG_FULLSCREEN) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/conversation/dynamicconcepts/GreetingAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.conversation.dynamicconcepts 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.LayoutInflater 10 | import android.view.ViewGroup 11 | 12 | import com.softbankrobotics.qisdktutorials.R 13 | 14 | import java.util.ArrayList 15 | 16 | /** 17 | * The adapter used to show greetings. 18 | */ 19 | internal class GreetingAdapter(private val onGreetingRemovedListener: OnGreetingRemovedListener) : RecyclerView.Adapter() { 20 | 21 | private val greetings: MutableList = ArrayList() 22 | 23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GreetingViewHolder { 24 | val view = LayoutInflater.from(parent.context).inflate(R.layout.greeting_layout, parent,false) 25 | return GreetingViewHolder(view, onGreetingRemovedListener) 26 | } 27 | 28 | override fun onBindViewHolder(holder: GreetingViewHolder, position: Int) { 29 | val greeting = greetings[position] 30 | holder.bind(greeting) 31 | } 32 | 33 | override fun getItemCount(): Int = greetings.size 34 | 35 | fun addGreeting(greeting: String) { 36 | greetings.add(greeting) 37 | notifyItemInserted(greetings.size - 1) 38 | } 39 | 40 | fun removeGreeting(greeting: String) { 41 | val index = greetings.indexOf(greeting) 42 | if (index != -1) { 43 | greetings.remove(greeting) 44 | notifyItemRemoved(index) 45 | } 46 | } 47 | 48 | fun containsGreeting(greeting: String): Boolean = greetings.contains(greeting) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/conversation/dynamicconcepts/GreetingViewHolder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.conversation.dynamicconcepts 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.View 10 | import kotlinx.android.synthetic.main.greeting_layout.view.* 11 | 12 | /** 13 | * The view holder to show a greeting. 14 | */ 15 | internal class GreetingViewHolder(itemView: View, private val onGreetingRemovedListener: OnGreetingRemovedListener?) : RecyclerView.ViewHolder(itemView) { 16 | 17 | /** 18 | * Binds a tutorial to the views. 19 | * @param greeting the greeting 20 | */ 21 | fun bind(greeting: String) { 22 | itemView.greeting_textview.text = greeting 23 | itemView.delete_button.setOnClickListener { onGreetingRemovedListener?.onGreetingRemoved(greeting) } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/conversation/dynamicconcepts/OnGreetingRemovedListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.conversation.dynamicconcepts 7 | 8 | /** 9 | * The listener used to handle a greeting removal. 10 | */ 11 | internal interface OnGreetingRemovedListener { 12 | /** 13 | * Called when a greeting is removed. 14 | * @param greeting the greeting 15 | */ 16 | fun onGreetingRemoved(greeting: String) 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/conversation/listen/ListenTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.conversation.listen 7 | 8 | 9 | import android.os.Bundle 10 | import android.util.Log 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.ListenBuilder 16 | import com.aldebaran.qi.sdk.builder.PhraseSetBuilder 17 | import com.aldebaran.qi.sdk.builder.SayBuilder 18 | import com.aldebaran.qi.sdk.util.PhraseSetUtil 19 | import com.softbankrobotics.qisdktutorials.R 20 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 21 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 22 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 23 | import kotlinx.android.synthetic.main.activity_autonomous_abilities_tutorial.* 24 | 25 | private const val TAG = "ListenTutorialActivity" 26 | 27 | /** 28 | * The activity for the Listen tutorial. 29 | */ 30 | class ListenTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 31 | 32 | private lateinit var conversationBinder: ConversationBinder 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | // Register the RobotLifecycleCallbacks to this Activity. 38 | QiSDK.register(this, this) 39 | } 40 | 41 | override fun onDestroy() { 42 | // Unregister the RobotLifecycleCallbacks for this Activity. 43 | QiSDK.unregister(this, this) 44 | super.onDestroy() 45 | } 46 | 47 | override val layoutId = R.layout.conversation_layout 48 | 49 | override fun onRobotFocusGained(qiContext: QiContext) { 50 | // Bind the conversational events to the view. 51 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 52 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 53 | 54 | val say = SayBuilder.with(qiContext) 55 | .withText("I can listen to you: say \"Yes\" or \"No\" to try.") 56 | .build() 57 | 58 | say.run() 59 | 60 | // Create the PhraseSet 1. 61 | val phraseSetYes = PhraseSetBuilder.with(qiContext) // Create the builder using the QiContext. 62 | .withTexts("yes", "OK", "alright", "let's do this") // Add the phrases Pepper will listen to. 63 | .build() // Build the PhraseSet. 64 | 65 | // Create the PhraseSet 2. 66 | val phraseSetNo = PhraseSetBuilder.with(qiContext) // Create the builder using the QiContext. 67 | .withTexts("no", "Sorry", "I can't") // Add the phrases Pepper will listen to. 68 | .build() // Build the PhraseSet. 69 | 70 | // Create a new listen action. 71 | val listen = ListenBuilder.with(qiContext) // Create the builder with the QiContext. 72 | .withPhraseSets(phraseSetYes, phraseSetNo) // Set the PhraseSets to listen to. 73 | .build() // Build the listen action. 74 | 75 | // Run the listen action and get the result. 76 | val listenResult = listen.run() 77 | 78 | val humanText = listenResult.heardPhrase.text 79 | Log.i(TAG, "Heard phrase: $humanText") 80 | 81 | // Identify the matched phrase set. 82 | val matchedPhraseSet = listenResult.matchedPhraseSet 83 | if (PhraseSetUtil.equals(matchedPhraseSet, phraseSetYes)) { 84 | val msg = "Heard phrase set: yes" 85 | Log.i(TAG, msg) 86 | displayLine(msg, ConversationItemType.INFO_LOG) 87 | } else if (PhraseSetUtil.equals(matchedPhraseSet, phraseSetNo)) { 88 | val msg = "Heard phrase set: no" 89 | Log.i(TAG, msg) 90 | displayLine(msg, ConversationItemType.INFO_LOG) 91 | } 92 | } 93 | 94 | override fun onRobotFocusLost() { 95 | conversationBinder.unbind() 96 | } 97 | 98 | override fun onRobotFocusRefused(reason: String) { 99 | // Nothing here. 100 | } 101 | 102 | private fun displayLine(text: String, type: ConversationItemType) { 103 | runOnUiThread { conversation_view.addLine(text, type) } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/conversation/qichatbot/QiChatbotTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.conversation.qichatbot 7 | 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.ChatBuilder 15 | import com.aldebaran.qi.sdk.builder.QiChatbotBuilder 16 | import com.aldebaran.qi.sdk.builder.SayBuilder 17 | import com.aldebaran.qi.sdk.builder.TopicBuilder 18 | import com.aldebaran.qi.sdk.`object`.conversation.Chat 19 | import com.softbankrobotics.qisdktutorials.R 20 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 21 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 22 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 23 | import kotlinx.android.synthetic.main.activity_autonomous_abilities_tutorial.* 24 | 25 | private const val TAG = "QiChatbotActivity" 26 | 27 | /** 28 | * The activity for the QiChatbot tutorial. 29 | */ 30 | class QiChatbotTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 31 | 32 | private var conversationBinder: ConversationBinder? = null 33 | 34 | // Store the Chat action. 35 | private lateinit var chat: Chat 36 | 37 | override fun onCreate(savedInstanceState: Bundle?) { 38 | super.onCreate(savedInstanceState) 39 | 40 | // Register the RobotLifecycleCallbacks to this Activity. 41 | QiSDK.register(this, this) 42 | } 43 | 44 | override fun onDestroy() { 45 | // Unregister the RobotLifecycleCallbacks for this Activity. 46 | QiSDK.unregister(this, this) 47 | super.onDestroy() 48 | } 49 | 50 | override val layoutId = R.layout.conversation_layout 51 | 52 | override fun onRobotFocusGained(qiContext: QiContext) { 53 | // Bind the conversational events to the view. 54 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 55 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 56 | 57 | val say = SayBuilder.with(qiContext) 58 | .withText("Say \"Hello\" to start the discussion.") 59 | .build() 60 | 61 | say.run() 62 | 63 | // Create a topic. 64 | val topic = TopicBuilder.with(qiContext) // Create the builder using the QiContext. 65 | .withResource(R.raw.greetings) // Set the topic resource. 66 | .build() // Build the topic. 67 | 68 | // Create a new QiChatbot. 69 | val qiChatbot = QiChatbotBuilder.with(qiContext) 70 | .withTopic(topic) 71 | .build() 72 | 73 | // Create a new Chat action. 74 | val chat = ChatBuilder.with(qiContext) 75 | .withChatbot(qiChatbot) 76 | .build() 77 | .also { this.chat = it } 78 | 79 | // Add an on started listener to the Chat action. 80 | chat.addOnStartedListener { 81 | val message = "Discussion started." 82 | Log.i(TAG, message) 83 | displayLine(message, ConversationItemType.INFO_LOG) 84 | } 85 | 86 | this.chat = chat 87 | 88 | // Run the Chat action asynchronously. 89 | val chatFuture = this.chat.async().run() 90 | 91 | // Add a lambda to the action execution. 92 | chatFuture.thenConsume { 93 | if (it.hasError()) { 94 | val message = "Discussion finished with error." 95 | Log.e(TAG, message, it.error) 96 | displayLine(message, ConversationItemType.ERROR_LOG) 97 | } 98 | } 99 | } 100 | 101 | override fun onRobotFocusLost() { 102 | conversationBinder?.unbind() 103 | 104 | // Remove the listeners from the Chat action. 105 | chat.removeAllOnStartedListeners() 106 | } 107 | 108 | override fun onRobotFocusRefused(reason: String) { 109 | // Nothing here. 110 | } 111 | 112 | private fun displayLine(text: String, type: ConversationItemType) { 113 | runOnUiThread { conversation_view.addLine(text, type) } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/conversation/qichatvariables/QiChatVariablesTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.conversation.qichatvariables 7 | 8 | import android.os.Bundle 9 | import android.view.inputmethod.EditorInfo 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.ChatBuilder 15 | import com.aldebaran.qi.sdk.builder.QiChatbotBuilder 16 | import com.aldebaran.qi.sdk.builder.SayBuilder 17 | import com.aldebaran.qi.sdk.builder.TopicBuilder 18 | import com.aldebaran.qi.sdk.`object`.conversation.AutonomousReactionImportance 19 | import com.aldebaran.qi.sdk.`object`.conversation.AutonomousReactionValidity 20 | import com.aldebaran.qi.sdk.`object`.conversation.Bookmark 21 | import com.aldebaran.qi.sdk.`object`.conversation.QiChatVariable 22 | import com.aldebaran.qi.sdk.`object`.conversation.QiChatbot 23 | import com.softbankrobotics.qisdktutorials.R 24 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 25 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 26 | import com.softbankrobotics.qisdktutorials.utils.KeyboardUtils 27 | import kotlinx.android.synthetic.main.activity_qi_chat_variables_tutorial.* 28 | 29 | /** 30 | * The activity for the QiChatVariables tutorial. 31 | */ 32 | class QiChatVariablesTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 33 | 34 | private lateinit var conversationBinder: ConversationBinder 35 | 36 | // Store the qiVariable. 37 | private var qiVariable: QiChatVariable? = null 38 | // Store the QiChatbot. 39 | private var qiChatbot: QiChatbot? = null 40 | // Store the Bookmark used to read the qiVariable. 41 | private var readBookmark: Bookmark? = null 42 | 43 | override fun onCreate(savedInstanceState: Bundle?) { 44 | super.onCreate(savedInstanceState) 45 | 46 | variable_edit_text.setOnEditorActionListener { _, actionId, _ -> 47 | if (actionId == EditorInfo.IME_ACTION_DONE) { 48 | retrieveAndAssignVariable() 49 | } 50 | false 51 | } 52 | 53 | // Assign qiVariable on assign button clicked. 54 | assign_button.setOnClickListener { retrieveAndAssignVariable() } 55 | 56 | // Register the RobotLifecycleCallbacks to this Activity. 57 | QiSDK.register(this, this) 58 | } 59 | 60 | override fun onDestroy() { 61 | // Unregister the RobotLifecycleCallbacks for this Activity. 62 | QiSDK.unregister(this, this) 63 | super.onDestroy() 64 | } 65 | 66 | override val layoutId = R.layout.activity_qi_chat_variables_tutorial 67 | 68 | override fun onRobotFocusGained(qiContext: QiContext) { 69 | // Bind the conversational events to the view. 70 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 71 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 72 | 73 | val say = SayBuilder.with(qiContext) 74 | .withText("Assign a value to the qiVariable.") 75 | .build() 76 | 77 | say.run() 78 | 79 | // Create a topic. 80 | val topic = TopicBuilder.with(qiContext) 81 | .withResource(R.raw.variable) 82 | .build() 83 | 84 | readBookmark = topic.bookmarks["read"] 85 | 86 | // Create a new QiChatbot. 87 | val qiChatbot = QiChatbotBuilder.with(qiContext) 88 | .withTopic(topic) 89 | .build() 90 | 91 | // Create a new Chat action. 92 | val chat = ChatBuilder.with(qiContext) 93 | .withChatbot(qiChatbot) 94 | .build() 95 | 96 | // Get the qiVariable. 97 | qiVariable = qiChatbot.variable("var") 98 | this.qiChatbot = qiChatbot 99 | 100 | // Run the Chat action asynchronously. 101 | chat.async().run() 102 | } 103 | 104 | override fun onRobotFocusLost() { 105 | conversationBinder.unbind() 106 | } 107 | 108 | override fun onRobotFocusRefused(reason: String) { 109 | // Nothing here. 110 | } 111 | 112 | private fun retrieveAndAssignVariable() { 113 | val value = variable_edit_text.text.toString() 114 | variable_edit_text.text.clear() 115 | KeyboardUtils.hideKeyboard(this@QiChatVariablesTutorialActivity) 116 | assignVariable(value) 117 | } 118 | 119 | private fun assignVariable(value: String) { 120 | // Set the value. 121 | qiVariable?.let { 122 | it.async().setValue(value).andThenConsume { 123 | // Read the value. 124 | qiChatbot?.async()?.goToBookmark(readBookmark, AutonomousReactionImportance.HIGH, AutonomousReactionValidity.IMMEDIATE) 125 | } 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/gettingstarted/HelloHumanTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.gettingstarted 7 | 8 | import android.os.Bundle 9 | 10 | import com.aldebaran.qi.sdk.QiContext 11 | import com.aldebaran.qi.sdk.QiSDK 12 | import com.aldebaran.qi.sdk.RobotLifecycleCallbacks 13 | import com.aldebaran.qi.sdk.builder.SayBuilder 14 | import com.softbankrobotics.qisdktutorials.R 15 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 16 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 17 | import kotlinx.android.synthetic.main.conversation_layout.* 18 | 19 | /** 20 | * The activity for the Hello human tutorial. 21 | */ 22 | class HelloHumanTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 23 | private var conversationBinder: ConversationBinder? = null 24 | 25 | override fun onCreate(savedInstanceState: Bundle?) { 26 | super.onCreate(savedInstanceState) 27 | 28 | // Register the RobotLifecycleCallbacks to this Activity. 29 | QiSDK.register(this, this) 30 | } 31 | 32 | override fun onDestroy() { 33 | // Unregister the RobotLifecycleCallbacks for this Activity. 34 | QiSDK.unregister(this, this) 35 | super.onDestroy() 36 | } 37 | 38 | override val layoutId = R.layout.conversation_layout 39 | 40 | override fun onRobotFocusGained(qiContext: QiContext) { 41 | // Bind the conversational events to the view. 42 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 43 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 44 | 45 | // Create a new say action. 46 | val say = SayBuilder.with(qiContext) // Create the builder with the context. 47 | .withText("Hello human!") // Set the text to say. 48 | .build() // Build the say action. 49 | 50 | // Execute the action. 51 | say.run() 52 | } 53 | 54 | override fun onRobotFocusLost() { 55 | conversationBinder?.unbind() 56 | } 57 | 58 | override fun onRobotFocusRefused(reason: String) { 59 | // Nothing here. 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/motion/animate/AnimateTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.motion.animate 7 | 8 | import android.media.MediaPlayer 9 | import android.os.Bundle 10 | import android.util.Log 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.AnimateBuilder 16 | import com.aldebaran.qi.sdk.builder.AnimationBuilder 17 | import com.aldebaran.qi.sdk.builder.SayBuilder 18 | import com.aldebaran.qi.sdk.`object`.actuation.Animate 19 | import com.softbankrobotics.qisdktutorials.R 20 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 21 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 22 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 23 | import kotlinx.android.synthetic.main.conversation_layout.* 24 | 25 | private const val TAG = "AnimateTutorialActivity" 26 | 27 | /** 28 | * The activity for the Animate tutorial (animation). 29 | */ 30 | class AnimateTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 31 | 32 | private var conversationBinder: ConversationBinder? = null 33 | private var mediaPlayer: MediaPlayer? = null 34 | 35 | // Store the Animate action. 36 | private var animate: Animate? = null 37 | 38 | override fun onCreate(savedInstanceState: Bundle?) { 39 | super.onCreate(savedInstanceState) 40 | 41 | // Register the RobotLifecycleCallbacks to this Activity. 42 | QiSDK.register(this, this) 43 | } 44 | 45 | override fun onStart() { 46 | super.onStart() 47 | mediaPlayer = MediaPlayer.create(this, R.raw.elephant_sound) 48 | } 49 | 50 | override fun onStop() { 51 | mediaPlayer?.release() 52 | mediaPlayer = null 53 | super.onStop() 54 | } 55 | 56 | override fun onDestroy() { 57 | // Unregister the RobotLifecycleCallbacks for this Activity. 58 | QiSDK.unregister(this, this) 59 | super.onDestroy() 60 | } 61 | 62 | override val layoutId = R.layout.conversation_layout 63 | 64 | override fun onRobotFocusGained(qiContext: QiContext) { 65 | // Bind the conversational events to the view. 66 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 67 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 68 | 69 | val say = SayBuilder.with(qiContext) 70 | .withText("I can perform animations: here is an elephant.") 71 | .build() 72 | 73 | say.run() 74 | 75 | // Create an animation. 76 | val animation = AnimationBuilder.with(qiContext) // Create the builder with the context. 77 | .withResources(R.raw.elephant_a001) // Set the animation resource. 78 | .build() // Build the animation. 79 | 80 | // Create an animate action. 81 | val animate = AnimateBuilder.with(qiContext) // Create the builder with the context. 82 | .withAnimation(animation) // Set the animation. 83 | .build() // Build the animate action. 84 | .also { this.animate = it } 85 | 86 | // Add an on started listener to the animate action. 87 | animate.addOnStartedListener { 88 | val message = "Animation started." 89 | Log.i(TAG, message) 90 | displayLine(message, ConversationItemType.INFO_LOG) 91 | 92 | mediaPlayer?.start() 93 | } 94 | this.animate = animate 95 | 96 | // Run the animate action asynchronously. 97 | val animateFuture = animate.async().run() 98 | 99 | // Add a lambda to the action execution. 100 | animateFuture.thenConsume { 101 | if (it.isSuccess) { 102 | val message = "Animation finished with success." 103 | Log.i(TAG, message) 104 | displayLine(message, ConversationItemType.INFO_LOG) 105 | } else if (it.hasError()) { 106 | val message = "Animation finished with error." 107 | Log.e(TAG, message, it.error) 108 | displayLine(message, ConversationItemType.ERROR_LOG) 109 | } 110 | } 111 | } 112 | 113 | override fun onRobotFocusLost() { 114 | conversationBinder?.unbind() 115 | 116 | // Remove on started listeners from the animate action. 117 | animate?.removeAllOnStartedListeners() 118 | } 119 | 120 | override fun onRobotFocusRefused(reason: String) { 121 | // Nothing here. 122 | } 123 | 124 | private fun displayLine(text: String, type: ConversationItemType) { 125 | runOnUiThread { conversation_view.addLine(text, type) } 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/motion/animationlabels/AnimationLabelActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.motion.animationlabels 7 | 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.AnimateBuilder 15 | import com.aldebaran.qi.sdk.builder.AnimationBuilder 16 | import com.aldebaran.qi.sdk.builder.SayBuilder 17 | import com.aldebaran.qi.sdk.`object`.actuation.Animate 18 | import com.softbankrobotics.qisdktutorials.R 19 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 20 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 21 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationView 22 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 23 | 24 | private const val TAG = "AnimationLabelActivity" 25 | 26 | class AnimationLabelActivity : TutorialActivity(), RobotLifecycleCallbacks { 27 | 28 | private lateinit var conversationView: ConversationView 29 | private var conversationBinder: ConversationBinder? = null 30 | 31 | // Store the Animate action. 32 | private var animate: Animate? = null 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | conversationView = findViewById(R.id.conversation_view) 38 | 39 | // Register the RobotLifecycleCallbacks to this Activity. 40 | QiSDK.register(this, this) 41 | } 42 | 43 | override fun onDestroy() { 44 | // Unregister the RobotLifecycleCallbacks for this Activity. 45 | QiSDK.unregister(this, this) 46 | super.onDestroy() 47 | } 48 | 49 | override val layoutId = R.layout.conversation_layout 50 | 51 | override fun onRobotFocusGained(qiContext: QiContext) { 52 | // Bind the conversational events to the view. 53 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 54 | conversationBinder = conversationView.bindConversationTo(conversationStatus) 55 | 56 | val say = SayBuilder.with(qiContext) 57 | .withText("I can trigger events using animation labels: I will synchronize my speech with my dance.") 58 | .build() 59 | 60 | say.run() 61 | 62 | // Create an animation. 63 | val animation = AnimationBuilder.with(qiContext) // Create the builder with the context. 64 | .withResources(R.raw.dance_b001) // Set the animation resource. 65 | .build() // Build the animation. 66 | 67 | // Create an animate action. 68 | val animate = AnimateBuilder.with(qiContext) // Create the builder with the context. 69 | .withAnimation(animation) // Set the animation. 70 | .build() // Build the animate action. 71 | 72 | // Say and display the name of the reached labels 73 | animate.addOnLabelReachedListener { label, _ -> 74 | val sayLabel = SayBuilder.with(qiContext) 75 | .withText(label) 76 | .build() 77 | 78 | sayLabel.async().run() 79 | } 80 | 81 | // Add an on started listener to the animate action. 82 | animate.addOnStartedListener { 83 | val message = "Animation started." 84 | Log.i(TAG, message) 85 | displayLine(message, ConversationItemType.INFO_LOG) 86 | } 87 | 88 | // Run the animate action asynchronously. 89 | val animateFuture = animate.async().run() 90 | 91 | this.animate = animate 92 | 93 | // Add a lambda to the action execution. 94 | animateFuture.thenConsume { 95 | if (it.isSuccess) { 96 | val message = "Animation finished with success." 97 | Log.i(TAG, message) 98 | displayLine(message, ConversationItemType.INFO_LOG) 99 | } else if (it.hasError()) { 100 | val message = "Animation finished with error." 101 | Log.e(TAG, message, it.error) 102 | displayLine(message, ConversationItemType.ERROR_LOG) 103 | } 104 | } 105 | } 106 | 107 | override fun onRobotFocusLost() { 108 | conversationBinder?.unbind() 109 | 110 | // Remove the signal listeners from the animate action. 111 | animate?.removeAllOnStartedListeners() 112 | animate?.removeAllOnLabelReachedListeners() 113 | } 114 | 115 | override fun onRobotFocusRefused(reason: String) { 116 | // Nothing here. 117 | } 118 | 119 | private fun displayLine(text: String, type: ConversationItemType) { 120 | runOnUiThread { conversationView.addLine(text, type) } 121 | } 122 | 123 | } -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/motion/gotoframe/GoToTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.motion.gotoframe 7 | 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.GoToBuilder 15 | import com.aldebaran.qi.sdk.builder.SayBuilder 16 | import com.aldebaran.qi.sdk.builder.TransformBuilder 17 | import com.aldebaran.qi.sdk.`object`.actuation.GoTo 18 | import com.softbankrobotics.qisdktutorials.R 19 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 20 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 21 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 22 | import kotlinx.android.synthetic.main.activity_autonomous_abilities_tutorial.* 23 | 24 | private const val TAG = "GoToTutorialActivity" 25 | 26 | /** 27 | * The activity for the GoTo tutorial. 28 | */ 29 | class GoToTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 30 | 31 | private var conversationBinder: ConversationBinder? = null 32 | 33 | // Store the GoTo action. 34 | private var goTo: GoTo? = null 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | 39 | // Register the RobotLifecycleCallbacks to this Activity. 40 | QiSDK.register(this, this) 41 | } 42 | 43 | override fun onDestroy() { 44 | // Unregister the RobotLifecycleCallbacks for this Activity. 45 | QiSDK.unregister(this, this) 46 | super.onDestroy() 47 | } 48 | 49 | override val layoutId = R.layout.conversation_layout 50 | 51 | override fun onRobotFocusGained(qiContext: QiContext) { 52 | // Bind the conversational events to the view. 53 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 54 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 55 | 56 | val say = SayBuilder.with(qiContext) 57 | .withText("I can move around: I will go 1 meter forward.") 58 | .build() 59 | 60 | say.run() 61 | 62 | // Get the Actuation service from the QiContext. 63 | val actuation = qiContext.actuation 64 | 65 | // Get the robot frame. 66 | val robotFrame = actuation.robotFrame() 67 | 68 | // Create a transform corresponding to a 1 meter forward translation. 69 | val transform = TransformBuilder.create() 70 | .fromXTranslation(1.0) 71 | 72 | // Get the Mapping service from the QiContext. 73 | val mapping = qiContext.mapping 74 | 75 | // Create a FreeFrame with the Mapping service. 76 | val targetFrame = mapping.makeFreeFrame() 77 | 78 | // Update the target location relatively to Pepper's current location. 79 | targetFrame.update(robotFrame, transform, 0L) 80 | 81 | // Create a GoTo action. 82 | val goTo = GoToBuilder.with(qiContext) // Create the builder with the QiContext. 83 | .withFrame(targetFrame.frame()) // Set the target frame. 84 | .build() // Build the GoTo action. 85 | 86 | // Add an on started listener on the GoTo action. 87 | goTo.addOnStartedListener { 88 | val message = "GoTo action started." 89 | Log.i(TAG, message) 90 | displayLine(message, ConversationItemType.INFO_LOG) 91 | } 92 | this.goTo = goTo 93 | 94 | // Execute the GoTo action asynchronously. 95 | val goToFuture = goTo.async().run() 96 | 97 | // Add a lambda to the action execution. 98 | goToFuture.thenConsume { 99 | if (it.isSuccess) { 100 | val message = "GoTo action finished with success." 101 | Log.i(TAG, message) 102 | displayLine(message, ConversationItemType.INFO_LOG) 103 | } else if (it.hasError()) { 104 | val message = "GoTo action finished with error." 105 | Log.e(TAG, message, it.error) 106 | displayLine(message, ConversationItemType.ERROR_LOG) 107 | } 108 | } 109 | } 110 | 111 | override fun onRobotFocusLost() { 112 | conversationBinder?.unbind() 113 | 114 | // Remove on started listeners from the GoTo action. 115 | goTo?.removeAllOnStartedListeners() 116 | } 117 | 118 | override fun onRobotFocusRefused(reason: String) { 119 | // Nothing here. 120 | } 121 | 122 | private fun displayLine(text: String, type: ConversationItemType) { 123 | runOnUiThread { conversation_view?.addLine(text, type) } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/motion/trajectory/TrajectoryTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.motion.trajectory 7 | 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.AnimateBuilder 15 | import com.aldebaran.qi.sdk.builder.AnimationBuilder 16 | import com.aldebaran.qi.sdk.builder.SayBuilder 17 | import com.aldebaran.qi.sdk.`object`.actuation.Animate 18 | import com.softbankrobotics.qisdktutorials.R 19 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 20 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 21 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 22 | import kotlinx.android.synthetic.main.activity_autonomous_abilities_tutorial.* 23 | 24 | private const val TAG = "TrajectoryActivity" 25 | 26 | /** 27 | * The activity for the Animate tutorial (trajectory). 28 | */ 29 | class TrajectoryTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 30 | 31 | private var conversationBinder: ConversationBinder? = null 32 | 33 | // Store the Animate action. 34 | private var animate: Animate? = null 35 | 36 | override fun onCreate(savedInstanceState: Bundle?) { 37 | super.onCreate(savedInstanceState) 38 | 39 | // Register the RobotLifecycleCallbacks to this Activity. 40 | QiSDK.register(this, this) 41 | } 42 | 43 | override fun onDestroy() { 44 | // Unregister the RobotLifecycleCallbacks for this Activity. 45 | QiSDK.unregister(this, this) 46 | super.onDestroy() 47 | } 48 | 49 | override val layoutId = R.layout.conversation_layout 50 | 51 | override fun onRobotFocusGained(qiContext: QiContext) { 52 | // Bind the conversational events to the view. 53 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 54 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 55 | 56 | val say = SayBuilder.with(qiContext) 57 | .withText("I can perform trajectories: I will move forward.") 58 | .build() 59 | 60 | say.run() 61 | 62 | // Create an animation. 63 | val animation = AnimationBuilder.with(qiContext) // Create the builder with the context. 64 | .withResources(R.raw.dance) // Set the animation resource. 65 | .build() // Build the animation. 66 | 67 | // Create an animate action. 68 | val animate = AnimateBuilder.with(qiContext) // Create the builder with the context. 69 | .withAnimation(animation) // Set the animation. 70 | .build() // Build the animate action. 71 | 72 | // Add an on started listener to the animate action. 73 | animate.addOnStartedListener { 74 | val message = "Animation started." 75 | Log.i(TAG, message) 76 | displayLine(message, ConversationItemType.INFO_LOG) 77 | } 78 | 79 | // Run the animate action asynchronously. 80 | val animateFuture = animate.async().run() 81 | 82 | this.animate = animate 83 | 84 | // Add a lambda to the action execution. 85 | animateFuture.thenConsume { 86 | if (it.isSuccess) { 87 | val message = "Animation finished with success." 88 | Log.i(TAG, message) 89 | displayLine(message, ConversationItemType.INFO_LOG) 90 | } else if (it.hasError()) { 91 | val message = "Animation finished with error." 92 | Log.e(TAG, message, it.error) 93 | displayLine(message, ConversationItemType.ERROR_LOG) 94 | } 95 | } 96 | } 97 | 98 | override fun onRobotFocusLost() { 99 | conversationBinder?.unbind() 100 | 101 | // Remove on started listeners from the animate action. 102 | animate?.removeAllOnStartedListeners() 103 | } 104 | 105 | override fun onRobotFocusRefused(reason: String) { 106 | // Nothing here. 107 | } 108 | 109 | private fun displayLine(text: String, type: ConversationItemType) { 110 | runOnUiThread { conversation_view.addLine(text, type) } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/emotiondetection/BasicEmotion.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.emotiondetection 7 | 8 | /** 9 | * Represent a basic emotion. 10 | */ 11 | enum class BasicEmotion { 12 | UNKNOWN, 13 | NEUTRAL, 14 | CONTENT, 15 | JOYFUL, 16 | SAD, 17 | ANGRY 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/emotiondetection/EmotionTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.emotiondetection 7 | 8 | import android.os.Bundle 9 | import androidx.annotation.DrawableRes 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.softbankrobotics.qisdktutorials.R 16 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 17 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 18 | import kotlinx.android.synthetic.main.activity_emotion_tutorial.* 19 | 20 | /** 21 | * The activity for the Emotion tutorial. 22 | */ 23 | class EmotionTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks, OnBasicEmotionChangedListener { 24 | 25 | // Store the basic emotion observer. 26 | private var basicEmotionObserver: BasicEmotionObserver? = null 27 | 28 | private lateinit var conversationBinder: ConversationBinder 29 | 30 | override fun onCreate(savedInstanceState: Bundle?) { 31 | super.onCreate(savedInstanceState) 32 | 33 | // Create the basic emotion observer and listen to it. 34 | basicEmotionObserver = BasicEmotionObserver() 35 | basicEmotionObserver?.listener = this 36 | 37 | // Register the RobotLifecycleCallbacks to this Activity. 38 | QiSDK.register(this, this) 39 | } 40 | 41 | override fun onDestroy() { 42 | // Stop listening to basic emotion observer and remove it. 43 | basicEmotionObserver?.listener = null 44 | basicEmotionObserver = null 45 | 46 | // Unregister the RobotLifecycleCallbacks for this Activity. 47 | QiSDK.unregister(this, this) 48 | super.onDestroy() 49 | } 50 | 51 | override val layoutId = R.layout.activity_emotion_tutorial 52 | 53 | override fun onRobotFocusGained(qiContext: QiContext) { 54 | // Bind the conversational events to the view. 55 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 56 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 57 | 58 | val say = SayBuilder.with(qiContext) 59 | .withText("I can display the basic emotions of the human I'm seeing. Try to express an emotion with your smile, your voice or by touching my sensors.") 60 | .build() 61 | 62 | say.run() 63 | 64 | // Start the basic emotion observation. 65 | basicEmotionObserver?.startObserving(qiContext) 66 | } 67 | 68 | override fun onRobotFocusLost() { 69 | conversationBinder.unbind() 70 | 71 | // Stop the basic emotion observation. 72 | basicEmotionObserver?.stopObserving() 73 | } 74 | 75 | override fun onRobotFocusRefused(reason: String) { 76 | // Nothing here. 77 | } 78 | 79 | override fun onBasicEmotionChanged(basicEmotion: BasicEmotion) { 80 | // Update basic emotion image. 81 | runOnUiThread { emotion_image_view.setImageResource(emotionImageRes(basicEmotion)) } 82 | } 83 | 84 | @DrawableRes 85 | private fun emotionImageRes(basicEmotion: BasicEmotion): Int { 86 | return when (basicEmotion) { 87 | BasicEmotion.UNKNOWN -> R.drawable.ic_icons_cute_anon_unknown 88 | BasicEmotion.NEUTRAL -> R.drawable.ic_icons_cute_anon_neutral 89 | BasicEmotion.CONTENT -> R.drawable.ic_icons_cute_anon_smile 90 | BasicEmotion.JOYFUL -> R.drawable.ic_icons_cute_anon_joyful 91 | BasicEmotion.SAD -> R.drawable.ic_icons_cute_anon_sad 92 | BasicEmotion.ANGRY -> R.drawable.ic_icons_cute_anon_anger 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/emotiondetection/OnBasicEmotionChangedListener.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.emotiondetection 7 | 8 | /** 9 | * Listener used to notify when the basic emotion changes. 10 | */ 11 | interface OnBasicEmotionChangedListener { 12 | fun onBasicEmotionChanged(basicEmotion: BasicEmotion) 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/humanawareness/HumanInfo.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.humanawareness 7 | 8 | import android.graphics.Bitmap 9 | 10 | import com.aldebaran.qi.sdk.`object`.human.AttentionState 11 | import com.aldebaran.qi.sdk.`object`.human.EngagementIntentionState 12 | import com.aldebaran.qi.sdk.`object`.human.ExcitementState 13 | import com.aldebaran.qi.sdk.`object`.human.Gender 14 | import com.aldebaran.qi.sdk.`object`.human.PleasureState 15 | import com.aldebaran.qi.sdk.`object`.human.SmileState 16 | 17 | /** 18 | * Represents the human information. 19 | */ 20 | data class HumanInfo(val age: Int, val gender: Gender, val pleasureState: PleasureState, 21 | val excitementState: ExcitementState, val engagementIntentionState: EngagementIntentionState, 22 | val smileState: SmileState, val attentionState: AttentionState, val distance: Double, var facePicture: Bitmap? = null) { 23 | 24 | /** 25 | * To clear the memory before setting a new bitmap 26 | * [https://developer.android.com/reference/android/graphics/Bitmap.html#recycle()](https://developer.android.com/reference/android/graphics/Bitmap.html#recycle()) 27 | */ 28 | fun clearMemory() { 29 | facePicture?.takeUnless { it.isRecycled } 30 | ?.let { 31 | it.recycle() 32 | facePicture = it 33 | facePicture = null 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/humanawareness/HumanInfoAdapter.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.humanawareness 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.LayoutInflater 10 | import android.view.ViewGroup 11 | 12 | import com.softbankrobotics.qisdktutorials.R 13 | 14 | import java.util.ArrayList 15 | 16 | /** 17 | * The adapter used to show humans information. 18 | */ 19 | internal class HumanInfoAdapter : RecyclerView.Adapter() { 20 | 21 | private var humanInfoList: List = ArrayList() 22 | 23 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HumanInfoViewHolder { 24 | val view = LayoutInflater.from(parent.context).inflate(R.layout.human_info_layout, parent, false) 25 | return HumanInfoViewHolder(view) 26 | } 27 | 28 | override fun onBindViewHolder(holder: HumanInfoViewHolder, position: Int) { 29 | val humanInfo = humanInfoList[position] 30 | holder.bind(humanInfo) 31 | } 32 | 33 | override fun getItemCount() = humanInfoList.size 34 | 35 | fun updateList(humanInfoList: List) { 36 | this.humanInfoList = humanInfoList 37 | notifyDataSetChanged() 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/humanawareness/HumanInfoViewHolder.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.humanawareness 7 | 8 | import androidx.recyclerview.widget.RecyclerView 9 | import android.view.View 10 | 11 | import com.softbankrobotics.qisdktutorials.R 12 | import kotlinx.android.synthetic.main.human_info_layout.view.* 13 | 14 | /** 15 | * The view holder to show human information. 16 | */ 17 | internal class HumanInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 18 | 19 | /** 20 | * Binds human information to the views. 21 | * 22 | * @param humanInfo the human information to bind 23 | */ 24 | fun bind(humanInfo: HumanInfo) { 25 | val resources = itemView.resources 26 | itemView.age_textview.text = resources.getQuantityString(R.plurals.age, humanInfo.age, humanInfo.age) 27 | itemView.gender_textview.text = resources.getString(R.string.gender, humanInfo.gender) 28 | itemView.pleasure_state_textview.text = resources.getString(R.string.pleasure_state, humanInfo.pleasureState) 29 | itemView.excitement_state_textview.text = resources.getString(R.string.excitement_state, humanInfo.excitementState) 30 | itemView.engagement_intention_state_textview.text = resources.getString(R.string.engagement_intention_state, humanInfo.engagementIntentionState) 31 | itemView.smile_state_textview.text = resources.getString(R.string.smile_state, humanInfo.smileState) 32 | itemView.attention_state_textview.text = resources.getString(R.string.attention_state, humanInfo.attentionState) 33 | itemView.distance_textview.text = resources.getString(R.string.distance, humanInfo.distance) 34 | //we should put image bitmap to null to avoid setting image on recycled bitmap 35 | itemView.face_imageview.setImageBitmap(null) 36 | if (humanInfo.facePicture == null) { 37 | itemView.face_imageview.setBackgroundResource(R.drawable.ic_icons_cute_anon_unknown) 38 | } else { 39 | itemView.face_imageview.setImageBitmap(humanInfo.facePicture) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorials/perceptions/touch/TouchTutorialActivity.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorials.perceptions.touch 7 | 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.`object`.touch.TouchSensor 16 | import com.softbankrobotics.qisdktutorials.R 17 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationBinder 18 | import com.softbankrobotics.qisdktutorials.ui.conversation.ConversationItemType 19 | import com.softbankrobotics.qisdktutorials.ui.tutorials.TutorialActivity 20 | import kotlinx.android.synthetic.main.activity_autonomous_abilities_tutorial.* 21 | 22 | private const val TAG = "TouchTutorialActivity" 23 | 24 | /** 25 | * The activity for the Touch tutorial. 26 | */ 27 | class TouchTutorialActivity : TutorialActivity(), RobotLifecycleCallbacks { 28 | 29 | private var conversationBinder: ConversationBinder? = null 30 | 31 | // Store the head touch sensor. 32 | private var headTouchSensor: TouchSensor? = null 33 | 34 | override fun onCreate(savedInstanceState: Bundle?) { 35 | super.onCreate(savedInstanceState) 36 | 37 | // Register the RobotLifecycleCallbacks to this Activity. 38 | QiSDK.register(this, this) 39 | } 40 | 41 | override fun onDestroy() { 42 | // Unregister the RobotLifecycleCallbacks for this Activity. 43 | QiSDK.unregister(this, this) 44 | super.onDestroy() 45 | } 46 | 47 | override val layoutId = R.layout.conversation_layout 48 | 49 | override fun onRobotFocusGained(qiContext: QiContext) { 50 | // Bind the conversational events to the view. 51 | val conversationStatus = qiContext.conversation.status(qiContext.robotContext) 52 | conversationBinder = conversation_view.bindConversationTo(conversationStatus) 53 | 54 | val say = SayBuilder.with(qiContext) 55 | .withText("I have touch sensors: try to touch my head.") 56 | .build() 57 | 58 | say.run() 59 | 60 | // Get the Touch service from the QiContext. 61 | val touch = qiContext.touch 62 | 63 | // Get the head touch sensor. 64 | val headTouchSensor = touch.getSensor("Head/Touch") 65 | // Add onStateChanged listener. 66 | headTouchSensor.addOnStateChangedListener { 67 | val message = "Sensor " + (if (it.touched) "touched" else "released") + " at ${it.time}" 68 | Log.i(TAG, message) 69 | displayLine(message, ConversationItemType.INFO_LOG) 70 | } 71 | this.headTouchSensor = headTouchSensor 72 | } 73 | 74 | override fun onRobotFocusLost() { 75 | conversationBinder?.unbind() 76 | 77 | // Remove onStateChanged listeners. 78 | headTouchSensor?.removeAllOnStateChangedListeners() 79 | } 80 | 81 | override fun onRobotFocusRefused(reason: String) { 82 | // Nothing here. 83 | } 84 | 85 | private fun displayLine(text: String, type: ConversationItemType) { 86 | runOnUiThread { conversation_view.addLine(text, type) } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/ui/tutorialtoolbar/TutorialToolbar.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.ui.tutorialtoolbar 7 | 8 | import android.content.Context 9 | import androidx.annotation.StringRes 10 | import androidx.core.content.ContextCompat 11 | import androidx.appcompat.widget.Toolbar 12 | import android.util.AttributeSet 13 | import android.view.View 14 | 15 | import com.softbankrobotics.qisdktutorials.R 16 | import com.softbankrobotics.qisdktutorials.model.data.TutorialLevel 17 | import kotlinx.android.synthetic.main.tutorial_toolbar.view.* 18 | 19 | class TutorialToolbar (context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : Toolbar(context, attrs, defStyleAttr) { 20 | 21 | init { 22 | View.inflate(context, R.layout.tutorial_toolbar, this) 23 | } 24 | 25 | constructor(context: Context): this(context, null) 26 | 27 | constructor(context: Context, attrs: AttributeSet?): this(context, attrs,0) 28 | 29 | override fun setNavigationOnClickListener(listener: OnClickListener) { 30 | back_arrow.setOnClickListener(listener) 31 | } 32 | 33 | fun setName(name: String) { 34 | title_textview.text = name 35 | invalidate() 36 | requestLayout() 37 | } 38 | 39 | fun setName(@StringRes resId: Int) { 40 | title_textview.text = resources.getString((resId)) 41 | invalidate() 42 | requestLayout() 43 | } 44 | 45 | fun setLevel(level: TutorialLevel) { 46 | when (level) { 47 | TutorialLevel.BASIC -> { 48 | level_textview.setText(R.string.toolbar_basic_level) 49 | background_view.setBackgroundColor(ContextCompat.getColor(context, R.color.basic_green)) 50 | } 51 | TutorialLevel.ADVANCED -> { 52 | level_textview.setText(R.string.toolbar_advanced_level) 53 | background_view.setBackgroundColor(ContextCompat.getColor(context, R.color.advanced_orange)) 54 | } 55 | } 56 | 57 | invalidate() 58 | requestLayout() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/utils/Constants.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.utils 7 | 8 | interface Constants { 9 | 10 | interface Intent { 11 | companion object { 12 | const val TUTORIAL_NAME_KEY = "TUTORIAL_NAME_KEY" 13 | const val TUTORIAL_LEVEL_KEY = "TUTORIAL_LEVEL_KEY" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/softbankrobotics/qisdktutorials/utils/KeyboardUtils.kt: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018 Softbank Robotics Europe 3 | * See COPYING for the license 4 | */ 5 | 6 | package com.softbankrobotics.qisdktutorials.utils 7 | 8 | import android.app.Activity 9 | import android.content.Context 10 | import android.view.inputmethod.InputMethodManager 11 | 12 | /** 13 | * Utilities for keyboard management. 14 | */ 15 | object KeyboardUtils { 16 | 17 | fun hideKeyboard(activity: Activity) { 18 | val view = activity.currentFocus 19 | if (view != null) { 20 | val imm = activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager 21 | imm.hideSoftInputFromWindow(view.windowToken, 0) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/res/color/button_text_color_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 15 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/color/navigation_tint_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/advanced_level_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/basic_level_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_background_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 15 | 17 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/button_shape_unselected.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/category_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 10 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty_divider_big.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty_divider_tutorials.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_arrow_back.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_close.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_check.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icons_cute_anon_anger.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 29 | 36 | 43 | 48 | 53 | 58 | 63 | 68 | 75 | 82 | 83 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icons_cute_anon_joyful.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 31 | 34 | 37 | 44 | 51 | 54 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icons_cute_anon_neutral.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 39 | 40 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icons_cute_anon_sad.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 37 | 44 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icons_cute_anon_smile.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 37 | 44 | 51 | 52 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_icons_cute_anon_unknown.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 25 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_img_icon_humanmen.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 37 | 40 | 43 | 46 | 51 | 58 | 65 | 72 | 79 | 86 | 89 | 90 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_img_icon_pepper.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_move.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_talk.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/navigation_background_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/sbr_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldebaran/qisdk-tutorials/5f8839a018516982d8672814bbd77e05fe44796b/app/src/main/res/drawable/sbr_logo.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/switch_level_shape.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldebaran/qisdk-tutorials/5f8839a018516982d8672814bbd77e05fe44796b/app/src/main/res/font/open_sans_bold.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_light_italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldebaran/qisdk-tutorials/5f8839a018516982d8672814bbd77e05fe44796b/app/src/main/res/font/open_sans_light_italic.ttf -------------------------------------------------------------------------------- /app/src/main/res/font/open_sans_semibold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aldebaran/qisdk-tutorials/5f8839a018516982d8672814bbd77e05fe44796b/app/src/main/res/font/open_sans_semibold.ttf -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_autonomous_abilities_tutorial.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 29 | 30 |