├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── map_nav
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ └── map.jpg
│ │ ├── values
│ │ │ └── strings.xml
│ │ └── layout
│ │ │ └── main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── rosjava
│ │ └── android_apps
│ │ └── map_nav
│ │ ├── InitialPoseSubscriberLayer.java
│ │ ├── MapManager.java
│ │ ├── MapPosePublisherLayer.java
│ │ ├── ViewControlLayer.java
│ │ └── MainActivity.java
└── build.gradle
├── make_a_map
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── map.jpg
│ │ │ ├── make_a_map_save.png
│ │ │ └── make_a_map_refresh.png
│ │ ├── values
│ │ │ └── strings.xml
│ │ └── layout
│ │ │ ├── name_map_dialog.xml
│ │ │ └── main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── rosjava
│ │ └── android_apps
│ │ └── make_a_map
│ │ ├── MapManager.java
│ │ ├── ViewControlLayer.java
│ │ └── MainActivity.java
└── build.gradle
├── map_manager
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ └── map.jpg
│ │ ├── values
│ │ │ └── strings.xml
│ │ └── layout
│ │ │ ├── name_map_dialog.xml
│ │ │ ├── map_list_item.xml
│ │ │ └── main.xml
│ │ ├── java
│ │ └── com
│ │ │ └── github
│ │ │ └── rosjava
│ │ │ └── android_apps
│ │ │ └── map_manager
│ │ │ ├── MapListData.java
│ │ │ ├── MapListArrayAdapter.java
│ │ │ ├── MapManager.java
│ │ │ └── MainActivity.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── teleop
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ └── teleop.png
│ │ ├── values
│ │ │ └── strings.xml
│ │ └── layout
│ │ │ └── main.xml
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── rosjava
│ │ └── android_apps
│ │ └── teleop
│ │ └── MainActivity.java
└── build.gradle
├── gradle.properties
├── .gitignore
├── CHANGELOG.rst
├── .project
├── CMakeLists.txt
├── .classpath
├── settings.gradle
├── package.xml
├── gradlew.bat
└── gradlew
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/map_nav/src/main/res/drawable/map.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/map_nav/src/main/res/drawable/map.jpg
--------------------------------------------------------------------------------
/make_a_map/src/main/res/drawable/map.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/make_a_map/src/main/res/drawable/map.jpg
--------------------------------------------------------------------------------
/map_manager/src/main/res/drawable/map.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/map_manager/src/main/res/drawable/map.jpg
--------------------------------------------------------------------------------
/teleop/src/main/res/drawable/teleop.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/teleop/src/main/res/drawable/teleop.png
--------------------------------------------------------------------------------
/make_a_map/src/main/res/drawable/make_a_map_save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/make_a_map/src/main/res/drawable/make_a_map_save.png
--------------------------------------------------------------------------------
/make_a_map/src/main/res/drawable/make_a_map_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rosjava/android_apps/HEAD/make_a_map/src/main/res/drawable/make_a_map_refresh.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.daemon=true
2 | # Disabling the SNI extension fixes "handshake alert: unrecognized_name" error
3 | # in Java 7.
4 | org.gradle.jvmargs=-XX:MaxPermSize=512m -Djsse.enableSNIExtension=false
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | gen
3 | build.xml
4 | local.properties
5 | proguard-project.txt
6 | .gradle
7 | build
8 |
9 | # These are Android Studio files, might be worth including these later.
10 | .idea
11 | *.iml
12 | build.log
13 | build-log.xml
14 | *~
15 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/CHANGELOG.rst:
--------------------------------------------------------------------------------
1 | Changelog
2 | =========
3 | 0.3.0 (2018-10-04)
4 | ------------------
5 | * Kinetic build, with support for Android P.
6 |
7 | 0.2.0 (2015-02-22)
8 | ------------------
9 | * First build on indigo
10 |
11 | 0.1.4 (2013-10-31)
12 | ------------------
13 | * use ROS_MAVEN_REPOSITORY
14 |
--------------------------------------------------------------------------------
/teleop/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Kill
4 | Teleop
5 | compressed_image
6 | cmd_vel
7 |
8 |
--------------------------------------------------------------------------------
/map_manager/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Kill
4 | Map Manager
5 |
6 | turtlebot_core_apps/android_map_manager
7 | map
8 | base_link
9 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | android_apps
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 |
15 | org.eclipse.jdt.core.javanature
16 |
17 |
18 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 2.8.3)
2 | project(android_apps)
3 |
4 | find_package(catkin REQUIRED rosjava_build_tools)
5 |
6 | catkin_android_setup(assembleRelease assembleDebug uploadArchives)
7 |
8 | catkin_package()
9 |
10 | ##############################################################################
11 | # Installation
12 | ##############################################################################
13 |
14 | install(DIRECTORY ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_MAVEN_DESTINATION}/com/github/rosjava/android_apps/
15 | DESTINATION ${CATKIN_GLOBAL_MAVEN_DESTINATION}/com/github/rosjava/android_apps)
16 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/make_a_map/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Kill
4 | Make A Map
5 |
6 | turtlebot_core_apps/android_make_a_map
7 | map
8 | base_link
9 | compressed_image
10 | cmd_vel
11 | map
12 | scan
13 | save_map
14 |
--------------------------------------------------------------------------------
/map_manager/src/main/java/com/github/rosjava/android_apps/map_manager/MapListData.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.map_manager;
2 |
3 | public class MapListData {
4 |
5 | private String text = null;
6 | private boolean isChecked = false;
7 | private int id;
8 |
9 | public String getText() {
10 | return text;
11 | }
12 | public int getId() {
13 | return id;
14 | }
15 |
16 | public boolean isChecked() {
17 | return isChecked;
18 | }
19 |
20 | public void setText(String text) {
21 | this.text = text;
22 | }
23 |
24 | public void setId(int id) {
25 | this.id = id;
26 | }
27 |
28 | public void setChecked(boolean isChecked) {
29 | this.isChecked = isChecked;
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2011 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | include 'teleop'
18 | include 'map_nav'
19 | include 'make_a_map'
20 | include 'map_manager'
21 |
--------------------------------------------------------------------------------
/make_a_map/src/main/res/layout/name_map_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
16 |
20 |
--------------------------------------------------------------------------------
/map_manager/src/main/res/layout/name_map_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
12 |
16 |
20 |
--------------------------------------------------------------------------------
/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | android_apps
4 | 0.3.0
5 |
6 | Applications for robot-android pairing..
7 |
8 | http://ros.org/wiki/android_apps
9 | https://github.com/rosjava/android_apps
10 | https://github.com/rosjava/android_apps/issues
11 | Daniel Stonier
12 | Daniel Stonier
13 | Kazuto Murase
14 | Apache 2.0
15 |
16 | catkin
17 | rosjava_build_tools
18 | rosjava_bootstrap
19 | android_core
20 | android_extras
21 | android_remocons
22 | rosjava_messages
23 |
24 |
--------------------------------------------------------------------------------
/map_manager/src/main/res/layout/map_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
17 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/map_nav/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Kill
4 | Map Nav
5 |
6 | turtlebot_core_apps/android_map_nav
7 | map
8 | base_footprint
9 | compressed_image
10 | cmd_vel
11 | map
12 | /move_base/local_costmap/costmap
13 | scan
14 | move_base/NavfnROS/plan
15 | initialpose
16 | move_base_simple/goal
17 | move_base/goal
18 | list_maps
19 | publish_map
20 |
21 |
--------------------------------------------------------------------------------
/teleop/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Yujin Robot.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | dependencies {
18 | compile 'com.github.rosjava.android_remocons:common_tools:[0.3,0.4)'
19 | compile 'org.ros.android_core:android_core_components:[0.4,0.5)'
20 | }
21 |
22 | apply plugin: 'com.android.application'
23 |
24 | android {
25 | compileSdkVersion 28
26 |
27 | defaultConfig {
28 | minSdkVersion 16
29 | targetSdkVersion 28
30 | versionCode 2
31 | versionName "1.0.0"
32 | }
33 | productFlavors {
34 | kinetic {
35 | applicationId "com.github.rosjava.android_apps.teleop.kinetic"
36 | }
37 | }
38 | lintOptions {
39 | abortOnError = false
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/map_manager/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Yujin Robot.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | dependencies {
17 | compile 'com.github.rosjava.android_remocons:common_tools:[0.3,0.4)'
18 | compile 'org.ros.android_core:android_core_components:[0.4,0.5)'
19 | compile 'org.ros.rosjava_messages:world_canvas_msgs:[0.2,0.3)'
20 | }
21 |
22 | apply plugin: 'com.android.application'
23 |
24 | android {
25 | compileSdkVersion 28
26 |
27 | defaultConfig {
28 | minSdkVersion 16
29 | targetSdkVersion 28
30 | versionCode 3
31 | versionName "1.0.0"
32 | }
33 | productFlavors {
34 | kinetic {
35 | applicationId "com.github.rosjava.android_apps.map_manager.kinetic"
36 | }
37 | }
38 | lintOptions {
39 | abortOnError = false
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/make_a_map/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Yujin Robot.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | dependencies {
18 | compile 'com.github.rosjava.android_remocons:common_tools:[0.3,0.4)'
19 | compile 'org.ros.android_core:android_core_components:[0.4,0.5)'
20 | compile 'org.ros.rosjava_core:rosjava_geometry:[0.3,0.4)'
21 | compile 'org.ros.rosjava_messages:map_store:[0.3,0.4)'
22 | compile 'org.ros.rosjava_messages:world_canvas_msgs:[0.2,0.3)'
23 | }
24 |
25 | apply plugin: 'com.android.application'
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | defaultConfig {
31 | minSdkVersion 16
32 | targetSdkVersion 28
33 | versionCode 3
34 | versionName "1.0.1"
35 | }
36 | productFlavors {
37 | kinetic {
38 | applicationId "com.github.rosjava.android_apps.make_a_map.kinetic"
39 | }
40 | }
41 | lintOptions {
42 | abortOnError = false
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/map_nav/build.gradle:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 Yujin Robot.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 | dependencies {
17 | compile 'com.github.rosjava.android_remocons:common_tools:[0.3,0.4)'
18 | compile 'org.ros.android_core:android_core_components:[0.4,0.5)'
19 | compile 'org.ros.rosjava_core:rosjava_geometry:[0.3,0.4)'
20 | compile 'org.ros.rosjava_messages:map_store:[0.3,0.4)'
21 | compile 'org.ros.rosjava_messages:move_base_msgs:[1.12,1.13)'
22 | compile 'org.ros.rosjava_messages:world_canvas_msgs:[0.2,0.3)'
23 | }
24 |
25 | apply plugin: 'com.android.application'
26 |
27 | android {
28 | compileSdkVersion 28
29 |
30 | defaultConfig {
31 | minSdkVersion 16
32 | targetSdkVersion 28
33 | versionCode 3
34 | versionName "1.0.0"
35 | }
36 | productFlavors {
37 | kinetic {
38 | applicationId "com.github.rosjava.android_apps.map_nav.kinetic"
39 | }
40 | }
41 | lintOptions {
42 | abortOnError = false
43 | }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/map_nav/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/teleop/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/make_a_map/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/map_manager/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
14 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/map_manager/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
28 |
35 |
36 |
41 |
51 |
--------------------------------------------------------------------------------
/map_nav/src/main/java/com/github/rosjava/android_apps/map_nav/InitialPoseSubscriberLayer.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.map_nav;
2 |
3 | import org.ros.android.view.visualization.VisualizationView;
4 | import org.ros.android.view.visualization.layer.SubscriberLayer;
5 | import org.ros.android.view.visualization.layer.TfLayer;
6 | import org.ros.android.view.visualization.shape.GoalShape;
7 | import org.ros.android.view.visualization.shape.Shape;
8 | import org.ros.message.MessageListener;
9 | import org.ros.namespace.GraphName;
10 | import org.ros.node.ConnectedNode;
11 | import org.ros.rosjava_geometry.FrameTransform;
12 | import org.ros.rosjava_geometry.Transform;
13 |
14 | import javax.microedition.khronos.opengles.GL10;
15 |
16 |
17 | public class InitialPoseSubscriberLayer extends
18 | SubscriberLayer implements TfLayer {
19 |
20 | private final GraphName targetFrame;
21 |
22 | private Shape shape;
23 |
24 | public InitialPoseSubscriberLayer(String topic, String robotFrame) {
25 | this(GraphName.of(topic), robotFrame);
26 | shape = new GoalShape();
27 | }
28 |
29 | public InitialPoseSubscriberLayer(GraphName topic, String robotFrame) {
30 | super(topic, "geometry_msgs/PoseWithCovarianceStamped");
31 | targetFrame = GraphName.of(robotFrame);
32 | }
33 |
34 | @Override
35 | public void draw(VisualizationView view, GL10 gl) {
36 | shape.draw(view, gl);
37 | }
38 |
39 | @Override
40 | public void onStart(final VisualizationView view, ConnectedNode connectedNode) {
41 | super.onStart(view, connectedNode);
42 | getSubscriber().addMessageListener(
43 | new MessageListener() {
44 | @Override
45 | public void onNewMessage(geometry_msgs.PoseWithCovarianceStamped pose) {
46 | GraphName source = GraphName.of(pose.getHeader()
47 | .getFrameId());
48 | FrameTransform frameTransform = view.getFrameTransformTree().transform(source, targetFrame);
49 | if (frameTransform != null) {
50 | Transform poseTransform = Transform
51 | .fromPoseMessage(pose.getPose().getPose());
52 | shape.setTransform(frameTransform.getTransform()
53 | .multiply(poseTransform));
54 | }
55 | }
56 | });
57 | }
58 |
59 | @Override
60 | public GraphName getFrame() {
61 | return targetFrame;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/teleop/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
29 |
30 |
31 |
36 |
37 |
43 |
44 |
50 |
51 |
55 |
56 |
63 |
64 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/map_manager/src/main/java/com/github/rosjava/android_apps/map_manager/MapListArrayAdapter.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.map_manager;
2 |
3 | import android.content.Context;
4 | import android.view.LayoutInflater;
5 | import android.view.View;
6 | import android.view.View.OnClickListener;
7 | import android.view.View.OnLongClickListener;
8 | import android.view.View.OnTouchListener;
9 | import android.view.ViewGroup;
10 | import android.widget.ArrayAdapter;
11 | import android.widget.RadioButton;
12 | import android.widget.TextView;
13 |
14 | import java.util.List;
15 |
16 | public class MapListArrayAdapter extends ArrayAdapter {
17 |
18 | private class ViewHolder {
19 | TextView textView;
20 | RadioButton radioButton;
21 | }
22 |
23 | private OnTouchListener touchListener;
24 | private OnLongClickListener longClickListener;
25 | private List mapList = null;
26 | private LayoutInflater inflator;
27 | private MainActivity context;
28 |
29 | public MapListArrayAdapter(MainActivity context, int resourceId,
30 | List mapList, OnTouchListener touchListener,OnLongClickListener longClickListener) {
31 | super(context, resourceId, mapList);
32 | this.touchListener = touchListener;
33 | this.longClickListener = longClickListener;
34 | this.mapList = mapList;
35 | this.context = context;
36 |
37 | }
38 |
39 | @Override
40 | public MapListData getItem(int position) {
41 | return mapList.get(position);
42 | }
43 |
44 | @Override
45 | public View getView(int position, View convertView, ViewGroup parent) {
46 | ViewHolder viewHolder;
47 |
48 | if (convertView == null) {
49 | inflator = (LayoutInflater) getContext().getSystemService(
50 | Context.LAYOUT_INFLATER_SERVICE);
51 | convertView = inflator.inflate(R.layout.map_list_item, null);
52 | viewHolder = new ViewHolder();
53 | viewHolder.textView = (TextView) convertView
54 | .findViewById(R.id.map_list_text);
55 | viewHolder.radioButton = (RadioButton) convertView
56 | .findViewById(R.id.map_list_button);
57 | convertView.setTag(viewHolder);
58 | } else {
59 | viewHolder = (ViewHolder) convertView.getTag();
60 | }
61 | final MapListData mapListData = (MapListData) getItem(position);
62 | viewHolder.textView.setText(mapListData.getText());
63 | viewHolder.radioButton.setChecked(mapListData.isChecked());
64 | viewHolder.radioButton.setOnClickListener(new OnClickListener() {
65 |
66 | @Override
67 | public void onClick(View view) {
68 | for (int i = 0; i < mapList.size(); i++) {
69 | mapList.get(i).setChecked(false);
70 | }
71 | mapListData.setChecked(true);
72 | notifyDataSetChanged();
73 | context.updateMapView(mapListData.getId());
74 |
75 | }
76 |
77 | });
78 | convertView.setId(position);
79 | convertView.setOnTouchListener(touchListener);
80 | convertView.setOnLongClickListener(longClickListener);
81 | return convertView;
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/make_a_map/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
30 |
31 |
39 |
40 |
47 |
48 |
49 |
54 |
55 |
61 |
62 |
69 |
70 |
75 |
76 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/map_nav/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
14 |
15 |
21 |
22 |
28 |
29 |
33 |
34 |
40 |
41 |
48 |
49 |
56 |
57 |
58 |
59 |
64 |
65 |
71 |
72 |
79 |
80 |
85 |
86 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/map_nav/src/main/java/com/github/rosjava/android_apps/map_nav/MapManager.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.map_nav;
2 |
3 | import android.content.Context;
4 |
5 | import com.github.rosjava.android_remocons.common_tools.apps.AppRemappings;
6 |
7 | import org.ros.exception.RosRuntimeException;
8 | import org.ros.exception.ServiceNotFoundException;
9 | import org.ros.namespace.GraphName;
10 | import org.ros.namespace.NameResolver;
11 | import org.ros.node.AbstractNodeMain;
12 | import org.ros.node.ConnectedNode;
13 | import org.ros.node.service.ServiceClient;
14 | import org.ros.node.service.ServiceResponseListener;
15 |
16 | import world_canvas_msgs.ListMaps;
17 | import world_canvas_msgs.ListMapsRequest;
18 | import world_canvas_msgs.ListMapsResponse;
19 | import world_canvas_msgs.PublishMap;
20 | import world_canvas_msgs.PublishMapRequest;
21 | import world_canvas_msgs.PublishMapResponse;
22 |
23 | public class MapManager extends AbstractNodeMain {
24 |
25 | private ConnectedNode connectedNode;
26 | private String function;
27 | private ServiceResponseListener listServiceResponseListener;
28 | private ServiceResponseListener publishServiceResponseListener;
29 |
30 | private String mapId;
31 | private String listSrvName;
32 | private String pubSrvName;
33 | private NameResolver nameResolver;
34 | private boolean nameResolverSet = false;
35 |
36 | public MapManager(final Context context, final AppRemappings remaps) {
37 | // Apply remappings
38 | listSrvName = remaps.get(context.getString(R.string.list_maps_srv));
39 | pubSrvName = remaps.get(context.getString(R.string.publish_map_srv));
40 | }
41 |
42 | public void setMapId(String mapId) {
43 | this.mapId = mapId;
44 | }
45 |
46 | public void setNameResolver(NameResolver newNameResolver) {
47 | nameResolver = newNameResolver;
48 | nameResolverSet = true;
49 | }
50 |
51 | public void setFunction(String function) {
52 | this.function = function;
53 | }
54 |
55 | public void setListService(
56 | ServiceResponseListener listServiceResponseListener) {
57 | this.listServiceResponseListener = listServiceResponseListener;
58 | }
59 |
60 | public void setPublishService(
61 | ServiceResponseListener publishServiceResponseListener) {
62 | this.publishServiceResponseListener = publishServiceResponseListener;
63 | }
64 |
65 | public void listMaps() {
66 | ServiceClient listMapsClient;
67 | try
68 | {
69 | if (nameResolverSet)
70 | {
71 | listSrvName = nameResolver.resolve(listSrvName).toString();
72 | }
73 | listMapsClient = connectedNode.newServiceClient(listSrvName, ListMaps._TYPE);
74 | } catch (ServiceNotFoundException e) {
75 | try {
76 | Thread.sleep(1000L);
77 | listMaps();
78 | return;
79 | } catch (Exception ex) {}
80 |
81 | e.printStackTrace();
82 | throw new RosRuntimeException(e);
83 | }
84 | final ListMapsRequest request = listMapsClient.newMessage();
85 | listMapsClient.call(request, listServiceResponseListener);
86 | }
87 |
88 | public void publishMap() {
89 | ServiceClient publishMapClient;
90 |
91 | try
92 | {
93 | if (nameResolverSet)
94 | {
95 | pubSrvName = nameResolver.resolve(pubSrvName).toString();
96 | }
97 | publishMapClient = connectedNode.newServiceClient(pubSrvName, PublishMap._TYPE);
98 | } catch (ServiceNotFoundException e) {
99 | try {
100 | Thread.sleep(1000L);
101 | listMaps();
102 | return;
103 | } catch (Exception ex) {}
104 | throw new RosRuntimeException(e);
105 | }
106 | final PublishMapRequest request = publishMapClient.newMessage();
107 | request.setMapId(mapId);
108 | publishMapClient.call(request, publishServiceResponseListener);
109 | }
110 |
111 |
112 |
113 | @Override
114 | public GraphName getDefaultNodeName() {
115 | return null;
116 | }
117 |
118 | public void onStart(final ConnectedNode connectedNode) {
119 | this.connectedNode = connectedNode;
120 | if (function.equals("list")) {
121 | listMaps();
122 | } else if (function.equals("publish")) {
123 | publishMap();
124 | }
125 | }
126 | }
127 |
128 |
--------------------------------------------------------------------------------
/teleop/src/main/java/com/github/rosjava/android_apps/teleop/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 OSRF.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package com.github.rosjava.android_apps.teleop;
18 |
19 | import android.os.Bundle;
20 | import android.view.Menu;
21 | import android.view.MenuItem;
22 | import android.view.View;
23 | import android.widget.Button;
24 |
25 | import com.github.rosjava.android_remocons.common_tools.apps.RosAppActivity;
26 |
27 | import org.ros.android.BitmapFromCompressedImage;
28 | import org.ros.android.view.RosImageView;
29 | import org.ros.android.view.VirtualJoystickView;
30 | import org.ros.namespace.NameResolver;
31 | import org.ros.node.NodeConfiguration;
32 | import org.ros.node.NodeMainExecutor;
33 |
34 | import java.io.IOException;
35 |
36 | /**
37 | * @author murase@jsk.imi.i.u-tokyo.ac.jp (Kazuto Murase)
38 | */
39 | public class MainActivity extends RosAppActivity {
40 | private RosImageView cameraView;
41 | private VirtualJoystickView virtualJoystickView;
42 | private Button backButton;
43 |
44 | public MainActivity() {
45 | // The RosActivity constructor configures the notification title and ticker messages.
46 | super("android teleop", "android teleop");
47 | }
48 |
49 | @SuppressWarnings("unchecked")
50 | @Override
51 | public void onCreate(Bundle savedInstanceState) {
52 |
53 | setDashboardResource(R.id.top_bar);
54 | setMainWindowResource(R.layout.main);
55 | super.onCreate(savedInstanceState);
56 |
57 | cameraView = (RosImageView) findViewById(R.id.image);
58 | cameraView.setMessageType(sensor_msgs.CompressedImage._TYPE);
59 | cameraView.setMessageToBitmapCallable(new BitmapFromCompressedImage());
60 | virtualJoystickView = (VirtualJoystickView) findViewById(R.id.virtual_joystick);
61 | backButton = (Button) findViewById(R.id.back_button);
62 | backButton.setOnClickListener(new View.OnClickListener() {
63 | @Override
64 | public void onClick(View view) {
65 | onBackPressed();
66 | }
67 | });
68 | }
69 |
70 | @Override
71 | protected void init(NodeMainExecutor nodeMainExecutor) {
72 |
73 | super.init(nodeMainExecutor);
74 |
75 | try {
76 | java.net.Socket socket = new java.net.Socket(getMasterUri().getHost(), getMasterUri().getPort());
77 | java.net.InetAddress local_network_address = socket.getLocalAddress();
78 | socket.close();
79 | NodeConfiguration nodeConfiguration =
80 | NodeConfiguration.newPublic(local_network_address.getHostAddress(), getMasterUri());
81 |
82 | String joyTopic = remaps.get(getString(R.string.joystick_topic));
83 | String camTopic = remaps.get(getString(R.string.camera_topic));
84 |
85 | NameResolver appNameSpace = getMasterNameSpace();
86 | joyTopic = appNameSpace.resolve(joyTopic).toString();
87 | camTopic = appNameSpace.resolve(camTopic).toString();
88 |
89 | cameraView.setTopicName(camTopic);
90 | virtualJoystickView.setTopicName(joyTopic);
91 |
92 | nodeMainExecutor.execute(cameraView, nodeConfiguration
93 | .setNodeName("android/camera_view"));
94 | nodeMainExecutor.execute(virtualJoystickView,
95 | nodeConfiguration.setNodeName("android/virtual_joystick"));
96 | } catch (IOException e) {
97 | // Socket problem
98 | }
99 |
100 | }
101 |
102 | @Override
103 | public boolean onCreateOptionsMenu(Menu menu){
104 | menu.add(0,0,0,R.string.stop_app);
105 |
106 | return super.onCreateOptionsMenu(menu);
107 | }
108 |
109 | @Override
110 | public boolean onOptionsItemSelected(MenuItem item){
111 | super.onOptionsItemSelected(item);
112 | switch (item.getItemId()){
113 | case 0:
114 | onDestroy();
115 | break;
116 | }
117 | return true;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/make_a_map/src/main/java/com/github/rosjava/android_apps/make_a_map/MapManager.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.make_a_map;
2 |
3 | import android.content.Context;
4 | import android.os.AsyncTask;
5 |
6 | import com.github.rosjava.android_remocons.common_tools.apps.AppRemappings;
7 |
8 | import org.ros.exception.RemoteException;
9 | import org.ros.exception.ServiceNotFoundException;
10 | import org.ros.namespace.GraphName;
11 | import org.ros.namespace.NameResolver;
12 | import org.ros.node.AbstractNodeMain;
13 | import org.ros.node.ConnectedNode;
14 | import org.ros.node.service.ServiceClient;
15 | import org.ros.node.service.ServiceResponseListener;
16 |
17 | import java.util.concurrent.ExecutionException;
18 | import java.util.concurrent.TimeUnit;
19 | import java.util.concurrent.TimeoutException;
20 |
21 | import world_canvas_msgs.SaveMap;
22 | import world_canvas_msgs.SaveMapRequest;
23 | import world_canvas_msgs.SaveMapResponse;
24 |
25 | public class MapManager extends AbstractNodeMain {
26 |
27 | private ConnectedNode connectedNode;
28 | private ServiceResponseListener saveServiceResponseListener;
29 |
30 | private String mapName;
31 | private String saveSrvName;
32 | private NameResolver nameResolver;
33 | private boolean nameResolverSet = false;
34 | private boolean waitingFlag = false;
35 |
36 | private StatusCallback statusCallback;
37 |
38 | public interface StatusCallback {
39 | public void timeoutCallback();
40 | public void onSuccessCallback(SaveMapResponse arg0);
41 | public void onFailureCallback(Exception e);
42 | }
43 | public void registerCallback(StatusCallback statusCallback) {
44 | this.statusCallback = statusCallback;
45 | }
46 |
47 | public MapManager(final Context context, final AppRemappings remaps) {
48 | // Apply remappings
49 | saveSrvName = remaps.get(context.getString(R.string.save_map_srv));
50 | mapName = "";
51 | }
52 |
53 | public void setMapName(String name) {
54 | mapName = name;
55 | }
56 |
57 | public void setNameResolver(NameResolver newNameResolver) {
58 | nameResolver = newNameResolver;
59 | nameResolverSet = true;
60 | }
61 |
62 | private void clearWaitFor(){
63 | waitingFlag = false;
64 | }
65 |
66 | private boolean waitFor(final int timeout) {
67 | waitingFlag = true;
68 | AsyncTask asyncTask = new AsyncTask() {
69 | @Override
70 | protected Boolean doInBackground(Void... params) {
71 | int count = 0;
72 | int timeout_count = timeout * 1000 / 200;
73 | while(waitingFlag){
74 | try { Thread.sleep(200); }
75 | catch (InterruptedException e) { return false; }
76 | if(count < timeout_count){
77 | count += 1;
78 | }
79 | else{
80 | return false;
81 | }
82 | }
83 | return true;
84 | }
85 | }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
86 | try {
87 | return asyncTask.get(timeout, TimeUnit.SECONDS);
88 | } catch (InterruptedException e) {
89 | return false;
90 | } catch (ExecutionException e) {
91 | return false;
92 | } catch (TimeoutException e) {
93 | return false;
94 | }
95 | }
96 |
97 | public void saveMap(){
98 | ServiceClient saveMapClient = null;
99 | if (connectedNode != null) {
100 | try{
101 | if (nameResolverSet){
102 | saveSrvName = nameResolver.resolve(saveSrvName).toString();
103 | }
104 | saveMapClient = connectedNode.newServiceClient(saveSrvName, SaveMap._TYPE);
105 | } catch (ServiceNotFoundException e) {
106 | try {
107 | Thread.sleep(1000L);
108 | } catch (Exception ex) {
109 | }
110 | statusCallback.onFailureCallback(e);
111 | }
112 | if (saveMapClient != null){
113 | final SaveMapRequest request = saveMapClient.newMessage();
114 | request.setMapName(mapName);
115 | saveMapClient.call(request, new ServiceResponseListener(){
116 | @Override
117 | public void onSuccess(SaveMapResponse saveMapResponse) {
118 | if (waitingFlag){
119 | clearWaitFor();
120 | statusCallback.onSuccessCallback(saveMapResponse);
121 | }
122 | }
123 | @Override
124 | public void onFailure(RemoteException e) {
125 | if (waitingFlag) {
126 | clearWaitFor();
127 | statusCallback.onFailureCallback(e);
128 | }
129 | }
130 | });
131 | if(!waitFor(10)){
132 | statusCallback.timeoutCallback();
133 | }
134 | }
135 |
136 | }
137 | }
138 | @Override
139 | public GraphName getDefaultNodeName() {
140 | return null;
141 | }
142 |
143 | @Override
144 | public void onStart(final ConnectedNode connectedNode){
145 | super.onStart(connectedNode);
146 | this.connectedNode = connectedNode;
147 | saveMap();
148 | }
149 | }
150 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/map_manager/src/main/java/com/github/rosjava/android_apps/map_manager/MapManager.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.map_manager;
2 |
3 | import org.ros.exception.RosRuntimeException;
4 | import org.ros.exception.ServiceNotFoundException;
5 | import org.ros.namespace.GraphName;
6 | import org.ros.namespace.NameResolver;
7 | import org.ros.node.AbstractNodeMain;
8 | import org.ros.node.ConnectedNode;
9 | import org.ros.node.service.ServiceClient;
10 | import org.ros.node.service.ServiceResponseListener;
11 |
12 | import world_canvas_msgs.DeleteMap;
13 | import world_canvas_msgs.DeleteMapRequest;
14 | import world_canvas_msgs.DeleteMapResponse;
15 | import world_canvas_msgs.ListMaps;
16 | import world_canvas_msgs.ListMapsRequest;
17 | import world_canvas_msgs.ListMapsResponse;
18 | import world_canvas_msgs.PublishMap;
19 | import world_canvas_msgs.PublishMapRequest;
20 | import world_canvas_msgs.PublishMapResponse;
21 | import world_canvas_msgs.RenameMap;
22 | import world_canvas_msgs.RenameMapRequest;
23 | import world_canvas_msgs.RenameMapResponse;
24 |
25 |
26 | public class MapManager extends AbstractNodeMain {
27 |
28 | private ConnectedNode connectedNode;
29 | private String function;
30 | private ServiceResponseListener listServiceResponseListener;
31 | private ServiceResponseListener publishServiceResponseListener;
32 | private ServiceResponseListener deleteServiceResponseListener;
33 | private ServiceResponseListener renameServiceResponseListener;
34 | private String mapId;
35 | private String mapName;
36 | private NameResolver nameResolver;
37 | private boolean nameResolverSet = false;
38 |
39 | public MapManager() {
40 | }
41 |
42 | public void setMapId(String mapId) {
43 | this.mapId = mapId;
44 | }
45 |
46 | public void setMapName(String mapName) {
47 | this.mapName = mapName;
48 | }
49 |
50 | public void setFunction(String function) {
51 | this.function = function;
52 | }
53 |
54 | public void setListService(
55 | ServiceResponseListener listServiceResponseListener) {
56 | this.listServiceResponseListener = listServiceResponseListener;
57 | }
58 |
59 | public void setPublishService(
60 | ServiceResponseListener publishServiceResponseListener) {
61 | this.publishServiceResponseListener = publishServiceResponseListener;
62 | }
63 |
64 | public void setDeleteService(
65 | ServiceResponseListener deleteServiceResponseListener) {
66 | this.deleteServiceResponseListener = deleteServiceResponseListener;
67 | }
68 |
69 | public void setRenameService(
70 | ServiceResponseListener renameServiceResponseListener) {
71 | this.renameServiceResponseListener = renameServiceResponseListener;
72 | }
73 |
74 | public void setNameResolver(NameResolver newNameResolver) {
75 | nameResolver = newNameResolver;
76 | nameResolverSet = true;
77 | }
78 |
79 | public void listMaps() {
80 | ServiceClient listMapsClient;
81 | try {
82 | String srvName = "list_maps";
83 | if (nameResolverSet)
84 | {
85 | srvName = nameResolver.resolve(srvName).toString();
86 | }
87 | listMapsClient = connectedNode.newServiceClient(srvName, ListMaps._TYPE);
88 | } catch (ServiceNotFoundException e) {
89 | try {
90 | Thread.sleep(1000L);
91 | listMaps();
92 | return;
93 | } catch (Exception ex) {}
94 |
95 | e.printStackTrace();
96 | throw new RosRuntimeException(e);
97 | }
98 | final ListMapsRequest request = listMapsClient.newMessage();
99 | listMapsClient.call(request, listServiceResponseListener);
100 | }
101 |
102 | public void publishMap() {
103 | ServiceClient publishMapClient;
104 |
105 | try {
106 | String srvName = "publish_map";
107 | if (nameResolverSet)
108 | {
109 | srvName = nameResolver.resolve(srvName).toString();
110 | }
111 | publishMapClient = connectedNode.newServiceClient(srvName, PublishMap._TYPE);
112 | } catch (ServiceNotFoundException e) {
113 | try {
114 | Thread.sleep(1000L);
115 | listMaps();
116 | return;
117 | } catch (Exception ex) {}
118 | throw new RosRuntimeException(e);
119 | }
120 | final PublishMapRequest request = publishMapClient.newMessage();
121 | request.setMapId(mapId);
122 | publishMapClient.call(request, publishServiceResponseListener);
123 | }
124 |
125 | public void deleteMap() {
126 | ServiceClient deleteMapClient;
127 |
128 | try {
129 | String srvName = "delete_map";
130 | if (nameResolverSet)
131 | {
132 | srvName = nameResolver.resolve(srvName).toString();
133 | }
134 | deleteMapClient = connectedNode.newServiceClient(srvName, DeleteMap._TYPE);
135 | } catch (ServiceNotFoundException e) {
136 | throw new RosRuntimeException(e);
137 | }
138 | final DeleteMapRequest request = deleteMapClient.newMessage();
139 | request.setMapId(mapId);
140 | deleteMapClient.call(request, deleteServiceResponseListener);
141 | }
142 |
143 | public void renameMap() {
144 | ServiceClient renameMapClient;
145 |
146 | try {
147 | String srvName = "rename_map";
148 | if (nameResolverSet)
149 | {
150 | srvName = nameResolver.resolve(srvName).toString();
151 | }
152 | renameMapClient = connectedNode.newServiceClient(srvName, RenameMap._TYPE);
153 | } catch (ServiceNotFoundException e) {
154 | throw new RosRuntimeException(e);
155 | }
156 | final RenameMapRequest request = renameMapClient.newMessage();
157 | request.setMapId(mapId);
158 | request.setNewName(mapName);
159 | renameMapClient.call(request, renameServiceResponseListener);
160 | }
161 |
162 | @Override
163 | public GraphName getDefaultNodeName() {
164 | return null;
165 | }
166 |
167 | public void onStart(final ConnectedNode connectedNode) {
168 | this.connectedNode = connectedNode;
169 | if (function.equals("list")) {
170 | listMaps();
171 | } else if (function.equals("publish")) {
172 | publishMap();
173 | } else if (function.equals("delete")) {
174 | deleteMap();
175 | } else if (function.equals("rename")) {
176 | renameMap();
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/map_nav/src/main/java/com/github/rosjava/android_apps/map_nav/MapPosePublisherLayer.java:
--------------------------------------------------------------------------------
1 | package com.github.rosjava.android_apps.map_nav;
2 |
3 | import android.content.Context;
4 | import android.view.GestureDetector;
5 | import android.view.MotionEvent;
6 |
7 | import com.github.rosjava.android_remocons.common_tools.apps.AppParameters;
8 | import com.github.rosjava.android_remocons.common_tools.apps.AppRemappings;
9 | import com.google.common.base.Preconditions;
10 |
11 | import org.ros.android.view.visualization.VisualizationView;
12 | import org.ros.android.view.visualization.layer.DefaultLayer;
13 | import org.ros.android.view.visualization.shape.PixelSpacePoseShape;
14 | import org.ros.android.view.visualization.shape.Shape;
15 | import org.ros.namespace.GraphName;
16 | import org.ros.namespace.NameResolver;
17 | import org.ros.node.ConnectedNode;
18 | import org.ros.node.Node;
19 | import org.ros.node.topic.Publisher;
20 | import org.ros.rosjava_geometry.Transform;
21 | import org.ros.rosjava_geometry.Vector3;
22 |
23 | import javax.microedition.khronos.opengles.GL10;
24 |
25 | import geometry_msgs.PoseStamped;
26 | import geometry_msgs.PoseWithCovarianceStamped;
27 | import move_base_msgs.MoveBaseActionGoal;
28 |
29 | //import com.github.rosjava.android_apps.application_management.rapp_manager.AppParameters;
30 | //import com.github.rosjava.android_apps.application_management.rapp_manager.AppRemappings;
31 |
32 | public class MapPosePublisherLayer extends DefaultLayer {
33 |
34 | private Shape shape;
35 | private Publisher initialPosePublisher;
36 | private Publisher androidGoalPublisher;
37 | private Publisher goalPublisher;
38 | private boolean visible;
39 | private NameResolver nameResolver;
40 | private GestureDetector gestureDetector;
41 | private Transform pose;
42 | private Transform fixedPose;
43 | private ConnectedNode connectedNode;
44 | private int mode;
45 | private static final int POSE_MODE = 0;
46 | private static final int GOAL_MODE = 1;
47 |
48 | private String mapFrame;
49 | private String robotFrame;
50 | private String initialPoseTopic;
51 | private String simpleGoalTopic;
52 | private String moveBaseGoalTopic;
53 |
54 | public MapPosePublisherLayer(final Context context,
55 | final NameResolver newNameResolver,
56 | final AppParameters params, final AppRemappings remaps) {
57 | this.nameResolver = newNameResolver;
58 | visible = false;
59 |
60 | this.mapFrame = (String) params.get("map_frame",context.getString(R.string.map_frame));
61 | this.robotFrame = (String) params.get("robot_frame", context.getString(R.string.robot_frame));
62 |
63 | this.initialPoseTopic = remaps.get(context.getString(R.string.initial_pose_topic));
64 | this.simpleGoalTopic = remaps.get(context.getString(R.string.simple_goal_topic));
65 | this.moveBaseGoalTopic = remaps.get(context.getString(R.string.move_base_goal_topic));
66 |
67 | }
68 |
69 | public void setPoseMode() {
70 | mode = POSE_MODE;
71 | }
72 |
73 | public void setGoalMode() {
74 | mode = GOAL_MODE;
75 | }
76 |
77 | @Override
78 | public void draw(VisualizationView view, GL10 gl) {
79 | if (visible) {
80 | Preconditions.checkNotNull(pose);
81 | shape.draw(view, gl);
82 | }
83 | }
84 |
85 | private double angle(double x1, double y1, double x2, double y2) {
86 | double deltaX = x1 - x2;
87 | double deltaY = y1 - y2;
88 | return Math.atan2(deltaY, deltaX);
89 | }
90 |
91 | @Override
92 | public boolean onTouchEvent(VisualizationView view, MotionEvent event) {
93 | if (visible) {
94 | Preconditions.checkNotNull(pose);
95 |
96 | Vector3 poseVector;
97 | Vector3 pointerVector;
98 |
99 | if (event.getAction() == MotionEvent.ACTION_MOVE) {
100 | poseVector = pose.apply(Vector3.zero());
101 | pointerVector = view.getCamera().toCameraFrame((int) event.getX(),
102 | (int) event.getY());
103 |
104 | double angle = angle(pointerVector.getX(),
105 | pointerVector.getY(), poseVector.getX(),
106 | poseVector.getY());
107 | pose = Transform.translation(poseVector).multiply(
108 | Transform.zRotation(angle));
109 |
110 | shape.setTransform(pose);
111 | return true;
112 | }
113 | if (event.getAction() == MotionEvent.ACTION_UP) {
114 |
115 | PoseStamped poseStamped;
116 | switch (mode) {
117 | case POSE_MODE:
118 | view.getCamera().setFrame(mapFrame);
119 | poseVector = fixedPose.apply(Vector3.zero());
120 | pointerVector = view.getCamera().toCameraFrame(
121 | (int) event.getX(), (int) event.getY());
122 | double angle2 = angle(pointerVector.getX(),
123 | pointerVector.getY(), poseVector.getX(),
124 | poseVector.getY());
125 | fixedPose = Transform.translation(poseVector).multiply(
126 | Transform.zRotation(angle2));
127 | view.getCamera().setFrame(robotFrame);
128 | poseStamped = fixedPose.toPoseStampedMessage(
129 | GraphName.of(robotFrame),
130 | connectedNode.getCurrentTime(),
131 | androidGoalPublisher.newMessage());
132 |
133 | PoseWithCovarianceStamped initialPose = initialPosePublisher.newMessage();
134 | initialPose.getHeader().setFrameId(mapFrame);
135 | initialPose.getPose().setPose(poseStamped.getPose());
136 | double[] covariance = initialPose.getPose().getCovariance();
137 | covariance[6 * 0 + 0] = 0.5 * 0.5;
138 | covariance[6 * 1 + 1] = 0.5 * 0.5;
139 | covariance[6 * 5 + 5] = (float) (Math.PI / 12.0 * Math.PI / 12.0);
140 |
141 | initialPosePublisher.publish(initialPose);
142 | break;
143 | case GOAL_MODE:
144 | poseStamped = pose.toPoseStampedMessage(
145 | GraphName.of(robotFrame),
146 | connectedNode.getCurrentTime(),
147 | androidGoalPublisher.newMessage());
148 | androidGoalPublisher.publish(poseStamped);
149 |
150 | move_base_msgs.MoveBaseActionGoal message = goalPublisher.newMessage();
151 | message.setHeader(poseStamped.getHeader());
152 | message.getGoalId().setStamp(connectedNode.getCurrentTime());
153 | message.getGoalId().setId("move_base/move_base_client_android"
154 | + connectedNode.getCurrentTime().toString());
155 | message.getGoal().setTargetPose(poseStamped);
156 | goalPublisher.publish(message);
157 | break;
158 | }
159 | visible = false;
160 | return true;
161 | }
162 | }
163 | gestureDetector.onTouchEvent(event);
164 | return false;
165 | }
166 |
167 | @Override
168 | public void onStart(final VisualizationView view, ConnectedNode connectedNode) {
169 | this.connectedNode = connectedNode;
170 | shape = new PixelSpacePoseShape();
171 | mode = GOAL_MODE;
172 |
173 | initialPosePublisher = connectedNode.newPublisher(nameResolver.resolve(initialPoseTopic).toString(),
174 | "geometry_msgs/PoseWithCovarianceStamped");
175 | androidGoalPublisher = connectedNode.newPublisher(nameResolver.resolve(simpleGoalTopic).toString(),
176 | "geometry_msgs/PoseStamped");
177 | goalPublisher = connectedNode.newPublisher(nameResolver.resolve(moveBaseGoalTopic).toString(),
178 | "move_base_msgs/MoveBaseActionGoal");
179 | view.post(new Runnable() {
180 | @Override
181 | public void run() {
182 | gestureDetector = new GestureDetector(view.getContext(),
183 | new GestureDetector.SimpleOnGestureListener() {
184 | @Override
185 | public void onLongPress(MotionEvent e) {
186 | pose = Transform.translation(view.getCamera().toCameraFrame(
187 | (int) e.getX(), (int) e.getY()));
188 | shape.setTransform(pose);
189 | view.getCamera().setFrame(mapFrame);
190 | fixedPose = Transform.translation(view.getCamera().toCameraFrame(
191 | (int) e.getX(), (int) e.getY()));
192 | view.getCamera().setFrame(robotFrame);
193 | visible = true;
194 | }
195 | });
196 | }
197 | });
198 | }
199 |
200 | @Override
201 | public void onShutdown(VisualizationView view, Node node) {
202 | initialPosePublisher.shutdown();
203 | androidGoalPublisher.shutdown();
204 | goalPublisher.shutdown();
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/make_a_map/src/main/java/com/github/rosjava/android_apps/make_a_map/ViewControlLayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 OSRF.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package com.github.rosjava.android_apps.make_a_map;
18 |
19 |
20 |
21 | import java.util.concurrent.ExecutorService;
22 | import android.content.Context;
23 | import android.view.GestureDetector;
24 | import android.view.MotionEvent;
25 | import android.view.ScaleGestureDetector;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 |
29 | import com.github.rosjava.android_remocons.common_tools.apps.AppParameters;
30 |
31 | import org.ros.android.view.RosImageView;
32 | import org.ros.android.view.visualization.RotateGestureDetector;
33 | import org.ros.android.view.visualization.VisualizationView;
34 | import org.ros.android.view.visualization.layer.CameraControlLayer;
35 | import org.ros.android.view.visualization.layer.CameraControlListener;
36 | import org.ros.concurrent.ListenerGroup;
37 | import org.ros.concurrent.SignalRunnable;
38 | import org.ros.node.ConnectedNode;
39 |
40 | /**
41 | * @author murase@jsk.imi.i.u-tokyo.ac.jp (Kazuto Murase)
42 | */
43 | public class ViewControlLayer extends CameraControlLayer {
44 |
45 | private final Context context;
46 | private final ListenerGroup listeners;
47 |
48 | private GestureDetector translateGestureDetector;
49 | private RotateGestureDetector rotateGestureDetector;
50 | private ScaleGestureDetector zoomGestureDetector;
51 |
52 | private RosImageView cameraView;
53 | private VisualizationView mapView;
54 | private ViewGroup mainLayout;
55 | private ViewGroup sideLayout;
56 | private boolean mapViewGestureAvaiable;
57 |
58 |
59 | private enum ViewMode {
60 | CAMERA, MAP
61 | };
62 | private ViewMode viewMode;
63 | private String robotFrame;
64 |
65 |
66 | public ViewControlLayer(final Context context,
67 | final ExecutorService executorService,
68 | final RosImageView cameraView,
69 | final VisualizationView mapView,
70 | final ViewGroup mainLayout,
71 | final ViewGroup sideLayout,
72 | final AppParameters params) {
73 |
74 | this.context = context;
75 |
76 | listeners = new ListenerGroup(executorService);
77 |
78 | this.cameraView = cameraView;
79 | this.mapView = mapView;
80 | this.mainLayout = mainLayout;
81 | this.sideLayout = sideLayout;
82 |
83 | viewMode = ViewMode.CAMERA;
84 | this.cameraView.setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View v){
87 | swapViews();
88 | }
89 | });
90 |
91 | this.mapView.setClickable(true);
92 | this.cameraView.setClickable(false);
93 | this.robotFrame = (String) params.get("robot_frame", context.getString(R.string.robot_frame));
94 | mapViewGestureAvaiable = false;
95 | }
96 |
97 |
98 | @Override
99 | public boolean onTouchEvent(VisualizationView view,MotionEvent event){
100 |
101 | if(event.getAction()==MotionEvent.ACTION_UP){
102 | mapViewGestureAvaiable = true;
103 | }
104 | if(viewMode == ViewMode.CAMERA){
105 | swapViews();
106 | return true;
107 | }
108 | else {
109 | if (translateGestureDetector == null || rotateGestureDetector == null
110 | || zoomGestureDetector == null) {
111 | return false;
112 | }
113 | return translateGestureDetector.onTouchEvent(event)
114 | || rotateGestureDetector.onTouchEvent(event) || zoomGestureDetector.onTouchEvent(event);
115 | }
116 | }
117 |
118 |
119 |
120 | /**
121 | * Swap the camera and map views.
122 | */
123 | private void swapViews() {
124 | // Figure out where the views were...
125 | ViewGroup mapViewParent;
126 | ViewGroup cameraViewParent;
127 |
128 | if (viewMode == ViewMode.CAMERA) {
129 |
130 | mapViewParent = sideLayout;
131 | cameraViewParent = mainLayout;
132 | } else {
133 |
134 | mapViewParent = mainLayout;
135 | cameraViewParent = sideLayout;
136 | }
137 | int mapViewIndex = mapViewParent.indexOfChild(mapView);
138 | int cameraViewIndex = cameraViewParent.indexOfChild(cameraView);
139 |
140 | // Remove the views from their old locations...
141 | mapViewParent.removeView(mapView);
142 | cameraViewParent.removeView(cameraView);
143 |
144 | // Add them to their new location...
145 | mapViewParent.addView(cameraView, mapViewIndex);
146 | cameraViewParent.addView(mapView , cameraViewIndex);
147 |
148 | // Remeber that we are in the other mode now.
149 | if (viewMode == ViewMode.CAMERA) {
150 | viewMode = ViewMode.MAP;
151 | mapViewGestureAvaiable = false;
152 | } else {
153 | viewMode = ViewMode.CAMERA;
154 | }
155 | mapView.getCamera().jumpToFrame(robotFrame);
156 | mapView.setClickable(viewMode != ViewMode.MAP);
157 | cameraView.setClickable(viewMode != ViewMode.CAMERA);
158 |
159 | }
160 |
161 | @Override
162 | public void onStart(final VisualizationView view, ConnectedNode connectedNode) {
163 | view.post(new Runnable() {
164 | @Override
165 | public void run() {
166 | translateGestureDetector =
167 | new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
168 | @Override
169 | public boolean onScroll(MotionEvent event1, MotionEvent event2,
170 | final float distanceX, final float distanceY) {
171 | if (mapViewGestureAvaiable) {
172 | view.getCamera().translate(-distanceX, distanceY);
173 | listeners.signal(new SignalRunnable() {
174 | @Override
175 | public void run(CameraControlListener listener) {
176 | listener.onTranslate(-distanceX, distanceY);
177 | }
178 | });
179 | return true;
180 | }
181 |
182 | return false;
183 | }
184 | });
185 | rotateGestureDetector =
186 | new RotateGestureDetector(new RotateGestureDetector.OnRotateGestureListener() {
187 | @Override
188 | public boolean onRotate(MotionEvent event1, MotionEvent event2,
189 | final double deltaAngle) {
190 | if (mapViewGestureAvaiable) {
191 | final float focusX = (event1.getX(0) + event1.getX(1)) / 2;
192 | final float focusY = (event1.getY(0) + event1.getY(1)) / 2;
193 | view.getCamera().rotate(focusX, focusY, deltaAngle);
194 | listeners.signal(new SignalRunnable() {
195 | @Override
196 | public void run(CameraControlListener listener) {
197 | listener.onRotate(focusX, focusY, deltaAngle);
198 | }
199 | });
200 | // Don't consume this event in order to allow the zoom gesture
201 | // to also be detected.
202 | return false;
203 | }
204 |
205 | return true;
206 | }
207 | });
208 | zoomGestureDetector =
209 | new ScaleGestureDetector(context,
210 | new ScaleGestureDetector.SimpleOnScaleGestureListener() {
211 | @Override
212 | public boolean onScale(ScaleGestureDetector detector) {
213 | if (!detector.isInProgress()) {
214 | return false;
215 | }
216 | if (mapViewGestureAvaiable) {
217 | final float focusX = detector.getFocusX();
218 | final float focusY = detector.getFocusY();
219 | final float factor = detector.getScaleFactor();
220 | view.getCamera().zoom(focusX, focusY, factor);
221 | listeners.signal(new SignalRunnable() {
222 | @Override
223 | public void run(CameraControlListener listener) {
224 | listener.onZoom(focusX, focusY, factor);
225 | }
226 | });
227 | return true;
228 | }
229 |
230 | return false;
231 | }
232 | });
233 | }
234 | });
235 | }
236 | }
--------------------------------------------------------------------------------
/map_nav/src/main/java/com/github/rosjava/android_apps/map_nav/ViewControlLayer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 OSRF.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package com.github.rosjava.android_apps.map_nav;
18 |
19 |
20 | import java.util.concurrent.ExecutorService;
21 |
22 | import android.content.Context;
23 | import android.view.GestureDetector;
24 | import android.view.MotionEvent;
25 | import android.view.ScaleGestureDetector;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 |
29 | import com.github.rosjava.android_remocons.common_tools.apps.AppParameters;
30 |
31 | import org.ros.android.view.RosImageView;
32 | import org.ros.android.view.visualization.RotateGestureDetector;
33 | import org.ros.android.view.visualization.VisualizationView;
34 | import org.ros.android.view.visualization.layer.CameraControlLayer;
35 | import org.ros.android.view.visualization.layer.CameraControlListener;
36 | import org.ros.concurrent.ListenerGroup;
37 | import org.ros.concurrent.SignalRunnable;
38 | import org.ros.node.ConnectedNode;
39 | import org.ros.rosjava_geometry.FrameTransformTree;
40 |
41 | /**
42 | * @author murase@jsk.imi.i.u-tokyo.ac.jp (Kazuto Murase)
43 | */
44 | public class ViewControlLayer extends CameraControlLayer {
45 |
46 | private final Context context;
47 | private final ListenerGroup listeners;
48 |
49 | private GestureDetector translateGestureDetector;
50 | private RotateGestureDetector rotateGestureDetector;
51 | private ScaleGestureDetector zoomGestureDetector;
52 |
53 | private RosImageView cameraView;
54 | private VisualizationView mapView;
55 | private ViewGroup mainLayout;
56 | private ViewGroup sideLayout;
57 | private boolean mapViewGestureAvailable;
58 | private String robotFrame;
59 |
60 | private enum ViewMode {
61 | CAMERA, MAP
62 | };
63 | private ViewMode viewMode;
64 |
65 |
66 | public ViewControlLayer(final Context context,
67 | final ExecutorService executorService,
68 | final RosImageView cameraView,
69 | final VisualizationView mapView,
70 | final ViewGroup mainLayout,
71 | final ViewGroup sideLayout,
72 | final AppParameters params) {
73 |
74 | this.context = context;
75 |
76 | listeners = new ListenerGroup(executorService);
77 |
78 | this.cameraView = cameraView;
79 | this.mapView = mapView;
80 | this.mainLayout = mainLayout;
81 | this.sideLayout = sideLayout;
82 |
83 | viewMode = ViewMode.CAMERA;
84 | this.cameraView.setOnClickListener(new View.OnClickListener() {
85 | @Override
86 | public void onClick(View v) {
87 | swapViews();
88 | }
89 | });
90 |
91 | this.mapView.setClickable(true);
92 | this.cameraView.setClickable(false);
93 | this.robotFrame = (String) params.get("robot_frame", context.getString(R.string.robot_frame));
94 | mapViewGestureAvailable = false;
95 | }
96 |
97 | @Override
98 | public boolean onTouchEvent(VisualizationView view, MotionEvent event) {
99 |
100 | if (event.getAction() == MotionEvent.ACTION_UP) {
101 | mapViewGestureAvailable = true;
102 | }
103 | if (viewMode == ViewMode.CAMERA) {
104 | swapViews();
105 | return true;
106 | } else {
107 | if (translateGestureDetector == null ||
108 | rotateGestureDetector == null ||
109 | zoomGestureDetector == null) {
110 | return false;
111 | }
112 | return translateGestureDetector.onTouchEvent(event) ||
113 | rotateGestureDetector.onTouchEvent(event) ||
114 | zoomGestureDetector.onTouchEvent(event);
115 | }
116 | }
117 |
118 | /**
119 | * Swap the camera and map views.
120 | */
121 | private void swapViews() {
122 | // Figure out where the views were...
123 | ViewGroup mapViewParent;
124 | ViewGroup cameraViewParent;
125 |
126 | if (viewMode == ViewMode.CAMERA) {
127 |
128 | mapViewParent = sideLayout;
129 | cameraViewParent = mainLayout;
130 | } else {
131 |
132 | mapViewParent = mainLayout;
133 | cameraViewParent = sideLayout;
134 | }
135 | int mapViewIndex = mapViewParent.indexOfChild(mapView);
136 | int cameraViewIndex = cameraViewParent.indexOfChild(cameraView);
137 |
138 | // Remove the views from their old locations...
139 | mapViewParent.removeView(mapView);
140 | cameraViewParent.removeView(cameraView);
141 |
142 | // Add them to their new location...
143 | mapViewParent.addView(cameraView, mapViewIndex);
144 | cameraViewParent.addView(mapView, cameraViewIndex);
145 |
146 | // Remeber that we are in the other mode now.
147 | if (viewMode == ViewMode.CAMERA) {
148 | viewMode = ViewMode.MAP;
149 | mapViewGestureAvailable = false;
150 | } else {
151 | viewMode = ViewMode.CAMERA;
152 | }
153 | mapView.getCamera().jumpToFrame(robotFrame);
154 | mapView.setClickable(viewMode != ViewMode.MAP);
155 | cameraView.setClickable(viewMode != ViewMode.CAMERA);
156 | }
157 |
158 | @Override
159 | public void onStart(final VisualizationView view, ConnectedNode connectedNode) {
160 | view.post(new Runnable() {
161 | @Override
162 | public void run() {
163 | translateGestureDetector =
164 | new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
165 | @Override
166 | public boolean onScroll(MotionEvent event1, MotionEvent event2,
167 | final float distanceX, final float distanceY) {
168 | if (mapViewGestureAvailable) {
169 | view.getCamera().translate(-distanceX, distanceY);
170 | listeners.signal(new SignalRunnable() {
171 | @Override
172 | public void run(CameraControlListener listener) {
173 | listener.onTranslate(-distanceX, distanceY);
174 | }
175 | });
176 | return true;
177 | }
178 |
179 | return false;
180 | }
181 | });
182 | rotateGestureDetector =
183 | new RotateGestureDetector(new RotateGestureDetector.OnRotateGestureListener() {
184 | @Override
185 | public boolean onRotate(MotionEvent event1, MotionEvent event2,
186 | final double deltaAngle) {
187 | if (mapViewGestureAvailable) {
188 | final float focusX = (event1.getX(0) + event1.getX(1)) / 2;
189 | final float focusY = (event1.getY(0) + event1.getY(1)) / 2;
190 | view.getCamera().rotate(focusX, focusY, deltaAngle);
191 | listeners.signal(new SignalRunnable() {
192 | @Override
193 | public void run(CameraControlListener listener) {
194 | listener.onRotate(focusX, focusY, deltaAngle);
195 | }
196 | });
197 | // Don't consume this event in order to allow the zoom gesture
198 | // to also be detected.
199 | return false;
200 | }
201 |
202 | return true;
203 | }
204 | });
205 | zoomGestureDetector =
206 | new ScaleGestureDetector(context,
207 | new ScaleGestureDetector.SimpleOnScaleGestureListener() {
208 | @Override
209 | public boolean onScale(ScaleGestureDetector detector) {
210 | if (!detector.isInProgress()) {
211 | return false;
212 | }
213 | if (mapViewGestureAvailable) {
214 | final float focusX = detector.getFocusX();
215 | final float focusY = detector.getFocusY();
216 | final float factor = detector.getScaleFactor();
217 | view.getCamera().zoom(focusX, focusY, factor);
218 | listeners.signal(new SignalRunnable() {
219 | @Override
220 | public void run(CameraControlListener listener) {
221 | listener.onZoom(focusX, focusY, factor);
222 | }
223 | });
224 | return true;
225 | }
226 |
227 | return false;
228 | }
229 | });
230 | }
231 | });
232 | }
233 | }
--------------------------------------------------------------------------------
/make_a_map/src/main/java/com/github/rosjava/android_apps/make_a_map/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 OSRF.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package com.github.rosjava.android_apps.make_a_map;
18 |
19 | import android.app.AlertDialog;
20 | import android.app.Dialog;
21 | import android.app.ProgressDialog;
22 | import android.content.DialogInterface;
23 | import android.os.Bundle;
24 | import android.util.Log;
25 | import android.view.KeyEvent;
26 | import android.view.Menu;
27 | import android.view.MenuItem;
28 | import android.view.View;
29 | import android.view.ViewGroup;
30 | import android.widget.Button;
31 | import android.widget.EditText;
32 | import android.widget.ImageButton;
33 | import android.widget.Toast;
34 |
35 | import com.github.rosjava.android_remocons.common_tools.apps.RosAppActivity;
36 | import com.google.common.collect.Lists;
37 |
38 | import org.ros.address.InetAddressFactory;
39 | import org.ros.android.BitmapFromCompressedImage;
40 | import org.ros.android.view.RosImageView;
41 | import org.ros.android.view.VirtualJoystickView;
42 | import org.ros.android.view.visualization.VisualizationView;
43 | import org.ros.android.view.visualization.layer.CameraControlListener;
44 | import org.ros.android.view.visualization.layer.LaserScanLayer;
45 | import org.ros.android.view.visualization.layer.Layer;
46 | import org.ros.android.view.visualization.layer.OccupancyGridLayer;
47 | import org.ros.android.view.visualization.layer.RobotLayer;
48 | import org.ros.namespace.NameResolver;
49 | import org.ros.node.NodeConfiguration;
50 | import org.ros.node.NodeMainExecutor;
51 | import org.ros.time.NtpTimeProvider;
52 | import org.ros.time.TimeProvider;
53 | import org.ros.time.WallTimeProvider;
54 |
55 | import java.util.concurrent.TimeUnit;
56 |
57 | import world_canvas_msgs.SaveMapResponse;
58 |
59 | /**
60 | * @author murase@jsk.imi.i.u-tokyo.ac.jp (Kazuto Murase)
61 | */
62 | public class MainActivity extends RosAppActivity {
63 |
64 | private static final int NAME_MAP_DIALOG_ID = 0;
65 |
66 | private RosImageView cameraView;
67 | private VirtualJoystickView virtualJoystickView;
68 | private VisualizationView mapView;
69 | private ViewGroup mainLayout;
70 | private ViewGroup sideLayout;
71 | private ImageButton refreshButton;
72 | private ImageButton saveButton;
73 | private Button backButton;
74 | private NodeMainExecutor nodeMainExecutor;
75 | private NodeConfiguration nodeConfiguration;
76 | private ProgressDialog waitingDialog;
77 | private AlertDialog notiDialog;
78 |
79 |
80 | private OccupancyGridLayer occupancyGridLayer = null;
81 | private LaserScanLayer laserScanLayer = null;
82 | private RobotLayer robotLayer = null;
83 |
84 | public MainActivity() {
85 | // The RosActivity constructor configures the notification title and
86 | // ticker
87 | // messages.
88 | super("Make a map", "Make a map");
89 |
90 | }
91 |
92 | @SuppressWarnings("unchecked")
93 | @Override
94 | public void onCreate(Bundle savedInstanceState) {
95 |
96 | String defaultRobotName = getString(R.string.default_robot);
97 | String defaultAppName = getString(R.string.default_app);
98 | setDefaultMasterName(defaultRobotName);
99 | setDefaultAppName(defaultAppName);
100 | setDashboardResource(R.id.top_bar);
101 | setMainWindowResource(R.layout.main);
102 |
103 | super.onCreate(savedInstanceState);
104 |
105 | cameraView = (RosImageView) findViewById(R.id.image);
106 | cameraView.setMessageType(sensor_msgs.CompressedImage._TYPE);
107 | cameraView.setMessageToBitmapCallable(new BitmapFromCompressedImage());
108 | virtualJoystickView = (VirtualJoystickView) findViewById(R.id.virtual_joystick);
109 | refreshButton = (ImageButton) findViewById(R.id.refresh_button);
110 | saveButton = (ImageButton) findViewById(R.id.save_map);
111 | backButton = (Button) findViewById(R.id.back_button);
112 |
113 | mapView = (VisualizationView) findViewById(R.id.map_view);
114 | mapView.onCreate(Lists.newArrayList());
115 |
116 | refreshButton.setOnClickListener(new View.OnClickListener() {
117 | @Override
118 | public void onClick(View view) {
119 | // TODO
120 | Toast.makeText(MainActivity.this, "refreshing map...",
121 | Toast.LENGTH_SHORT).show();
122 | mapView.getCamera().jumpToFrame((String) params.get("map_frame", getString(R.string.map_frame)));
123 | }
124 | });
125 |
126 | saveButton.setOnClickListener(new View.OnClickListener() {
127 | @Override
128 | public void onClick(View view) {
129 | showDialog(NAME_MAP_DIALOG_ID);
130 |
131 | }
132 |
133 | });
134 |
135 | backButton.setOnClickListener(new View.OnClickListener() {
136 | @Override
137 | public void onClick(View view) {
138 | onBackPressed();
139 | }
140 | });
141 |
142 | mapView.getCamera().jumpToFrame((String) params.get("map_frame", getString(R.string.map_frame)));
143 |
144 | mainLayout = (ViewGroup) findViewById(R.id.main_layout);
145 | sideLayout = (ViewGroup) findViewById(R.id.side_layout);
146 | }
147 |
148 | @Override
149 | protected Dialog onCreateDialog(int id) {
150 | Dialog dialog;
151 | Button button;
152 |
153 | switch (id) {
154 | case NAME_MAP_DIALOG_ID:
155 | dialog = new Dialog(this);
156 | dialog.setContentView(R.layout.name_map_dialog);
157 | dialog.setTitle("Save Map");
158 | final EditText nameField = (EditText) dialog
159 | .findViewById(R.id.name_editor);
160 |
161 | nameField.setOnKeyListener(new View.OnKeyListener() {
162 | @Override
163 | public boolean onKey(final View view, int keyCode,
164 | KeyEvent event) {
165 | if (event.getAction() == KeyEvent.ACTION_DOWN
166 | && keyCode == KeyEvent.KEYCODE_ENTER) {
167 | safeShowWaitingDialog("Saving map...");
168 | try {
169 | final MapManager mapManager = new MapManager(MainActivity.this, remaps);
170 | String name = nameField.getText().toString();
171 | if (name != null) {
172 | mapManager.setMapName(name);
173 | }
174 | mapManager.setNameResolver(getMasterNameSpace());
175 | mapManager.registerCallback(new MapManager.StatusCallback() {
176 | @Override
177 | public void timeoutCallback() {
178 | safeDismissWaitingDialog();
179 | safeShowNotiDialog("Error", "Timeout");
180 | }
181 | @Override
182 | public void onSuccessCallback(SaveMapResponse arg0) {
183 | safeDismissWaitingDialog();
184 | safeShowNotiDialog("Success", "Map saving success!");
185 | }
186 | @Override
187 | public void onFailureCallback(Exception e) {
188 | safeDismissWaitingDialog();
189 | safeShowNotiDialog("Error", e.getMessage());
190 | }
191 | });
192 |
193 | nodeMainExecutor.execute(mapManager,
194 | nodeConfiguration.setNodeName("android/save_map"));
195 |
196 | } catch (Exception e) {
197 | e.printStackTrace();
198 | safeShowNotiDialog("Error", "Error during saving: " + e.toString());
199 | }
200 |
201 | removeDialog(NAME_MAP_DIALOG_ID);
202 | return true;
203 | } else {
204 | return false;
205 | }
206 | }
207 | });
208 | button = (Button) dialog.findViewById(R.id.cancel_button);
209 | button.setOnClickListener(new View.OnClickListener() {
210 | @Override
211 | public void onClick(View v) {
212 | removeDialog(NAME_MAP_DIALOG_ID);
213 | }
214 | });
215 | break;
216 | default:
217 | dialog = null;
218 | }
219 | return dialog;
220 | }
221 |
222 | private void safeDismissWaitingDialog() {
223 | runOnUiThread(new Runnable() {
224 | @Override
225 | public void run() {
226 | if (waitingDialog != null) {
227 | waitingDialog.dismiss();
228 | waitingDialog = null;
229 | }
230 | }
231 | });
232 | }
233 |
234 | private void safeShowWaitingDialog(final CharSequence message) {
235 | runOnUiThread(new Runnable() {
236 | @Override
237 | public void run() {
238 | if (waitingDialog != null) {
239 | waitingDialog.dismiss();
240 | waitingDialog = null;
241 | }
242 | waitingDialog = ProgressDialog.show(MainActivity.this, "",
243 | message, true);
244 | }
245 | });
246 | }
247 |
248 | private void safeShowNotiDialog(final String title, final CharSequence message) {
249 | runOnUiThread(new Runnable() {
250 | @Override
251 | public void run() {
252 | if (notiDialog != null) {
253 | notiDialog.dismiss();
254 | notiDialog = null;
255 | }
256 | if (waitingDialog != null) {
257 | waitingDialog.dismiss();
258 | waitingDialog = null;
259 | }
260 | AlertDialog.Builder dialog = new AlertDialog.Builder(
261 | MainActivity.this);
262 | dialog.setTitle(title);
263 | dialog.setMessage(message);
264 | dialog.setNeutralButton("Ok",
265 | new DialogInterface.OnClickListener() {
266 | @Override
267 | public void onClick(DialogInterface dlog, int i) {
268 | dlog.dismiss();
269 | }
270 | });
271 | notiDialog = dialog.show();
272 | }
273 | });
274 | }
275 |
276 | @Override
277 | protected void init(NodeMainExecutor nodeMainExecutor) {
278 |
279 | super.init(nodeMainExecutor);
280 | this.nodeMainExecutor = nodeMainExecutor;
281 |
282 | nodeConfiguration = NodeConfiguration.newPublic(InetAddressFactory
283 | .newNonLoopback().getHostAddress(), getMasterUri());
284 |
285 | String joyTopic = remaps.get(getString(R.string.joystick_topic));
286 | String camTopic = remaps.get(getString(R.string.camera_topic));
287 |
288 | NameResolver appNameSpace = getMasterNameSpace();
289 | joyTopic = appNameSpace.resolve(joyTopic).toString();
290 | camTopic = appNameSpace.resolve(camTopic).toString();
291 | cameraView.setTopicName(camTopic);
292 | virtualJoystickView.setTopicName(joyTopic);
293 |
294 | nodeMainExecutor.execute(cameraView,
295 | nodeConfiguration.setNodeName("android/camera_view"));
296 | nodeMainExecutor.execute(virtualJoystickView,
297 | nodeConfiguration.setNodeName("android/virtual_joystick"));
298 |
299 | ViewControlLayer viewControlLayer = new ViewControlLayer(this,
300 | nodeMainExecutor.getScheduledExecutorService(), cameraView,
301 | mapView, mainLayout, sideLayout, params);
302 |
303 | String mapTopic = remaps.get(getString(R.string.map_topic));
304 | String scanTopic = remaps.get(getString(R.string.scan_topic));
305 | String robotFrame = (String) params.get("robot_frame", getString(R.string.robot_frame));
306 |
307 | occupancyGridLayer = new OccupancyGridLayer(appNameSpace.resolve(mapTopic).toString());
308 | laserScanLayer = new LaserScanLayer(appNameSpace.resolve(scanTopic).toString());
309 | robotLayer = new RobotLayer(robotFrame);
310 |
311 | mapView.addLayer(viewControlLayer);
312 | mapView.addLayer(occupancyGridLayer);
313 | mapView.addLayer(laserScanLayer);
314 | mapView.addLayer(robotLayer);
315 |
316 | mapView.init(nodeMainExecutor);
317 | viewControlLayer.addListener(new CameraControlListener() {
318 | @Override
319 | public void onZoom(float focusX, float focusY, float factor) {}
320 | @Override
321 | public void onDoubleTap(float x, float y) {}
322 | @Override
323 | public void onTranslate(float distanceX, float distanceY) {}
324 | @Override
325 | public void onRotate(float focusX, float focusY, double deltaAngle) {}
326 | });
327 |
328 | TimeProvider timeProvider = null;
329 | try {
330 | NtpTimeProvider ntpTimeProvider = new NtpTimeProvider(
331 | InetAddressFactory.newFromHostString("pool.ntp.org"),
332 | nodeMainExecutor.getScheduledExecutorService());
333 | ntpTimeProvider.startPeriodicUpdates(1, TimeUnit.MINUTES);
334 | timeProvider = ntpTimeProvider;
335 | } catch (Throwable t) {
336 | Log.w("MakeAMap", "Unable to use NTP provider, using Wall Time. Error: " + t.getMessage(), t);
337 | timeProvider = new WallTimeProvider();
338 | }
339 | nodeConfiguration.setTimeProvider(timeProvider);
340 |
341 | nodeMainExecutor.execute(mapView, nodeConfiguration.setNodeName("android/map_view"));
342 | }
343 |
344 | @Override
345 | public boolean onCreateOptionsMenu(Menu menu) {
346 | menu.add(0, 0, 0, R.string.stop_app);
347 | return super.onCreateOptionsMenu(menu);
348 | }
349 |
350 | @Override
351 | public boolean onOptionsItemSelected(MenuItem item) {
352 | super.onOptionsItemSelected(item);
353 | switch (item.getItemId()) {
354 | case 0:
355 | onDestroy();
356 | break;
357 | }
358 | return true;
359 | }
360 | }
361 |
--------------------------------------------------------------------------------
/map_nav/src/main/java/com/github/rosjava/android_apps/map_nav/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 OSRF.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package com.github.rosjava.android_apps.map_nav;
18 |
19 | import android.app.AlertDialog;
20 | import android.app.ProgressDialog;
21 | import android.content.DialogInterface;
22 | import android.os.Bundle;
23 | import android.util.Log;
24 | import android.view.Menu;
25 | import android.view.MenuItem;
26 | import android.view.View;
27 | import android.view.ViewGroup;
28 | import android.widget.Button;
29 |
30 | import com.github.rosjava.android_remocons.common_tools.apps.RosAppActivity;
31 | import com.google.common.collect.Lists;
32 |
33 | import org.ros.address.InetAddressFactory;
34 | import org.ros.android.BitmapFromCompressedImage;
35 | import org.ros.android.view.RosImageView;
36 | import org.ros.android.view.VirtualJoystickView;
37 | import org.ros.android.view.visualization.VisualizationView;
38 | import org.ros.android.view.visualization.layer.CameraControlListener;
39 | import org.ros.android.view.visualization.layer.LaserScanLayer;
40 | import org.ros.android.view.visualization.layer.Layer;
41 | import org.ros.android.view.visualization.layer.OccupancyGridLayer;
42 | import org.ros.android.view.visualization.layer.PathLayer;
43 | import org.ros.exception.RemoteException;
44 | import org.ros.namespace.NameResolver;
45 | import org.ros.node.NodeConfiguration;
46 | import org.ros.node.NodeMainExecutor;
47 | import org.ros.node.service.ServiceResponseListener;
48 | import org.ros.time.NtpTimeProvider;
49 | import org.ros.time.TimeProvider;
50 | import org.ros.time.WallTimeProvider;
51 |
52 | import java.sql.Date;
53 | import java.text.DateFormat;
54 | import java.util.List;
55 | import java.util.concurrent.TimeUnit;
56 |
57 | import world_canvas_msgs.ListMapsResponse;
58 | import world_canvas_msgs.MapListEntry;
59 | import world_canvas_msgs.PublishMapResponse;
60 |
61 | /**
62 | * @author murase@jsk.imi.i.u-tokyo.ac.jp (Kazuto Murase)
63 | */
64 | public class MainActivity extends RosAppActivity {
65 | private static final String TAG = "MapNav";
66 |
67 | private RosImageView cameraView;
68 | private VirtualJoystickView virtualJoystickView;
69 | private VisualizationView mapView;
70 | private ViewGroup mainLayout;
71 | private ViewGroup sideLayout;
72 | private Button backButton;
73 | private Button chooseMapButton;
74 | private com.github.rosjava.android_apps.map_nav.MapPosePublisherLayer mapPosePublisherLayer;
75 | private ProgressDialog waitingDialog;
76 | private AlertDialog chooseMapDialog;
77 | private NodeMainExecutor nodeMainExecutor;
78 | private NodeConfiguration nodeConfiguration;
79 |
80 | public MainActivity() {
81 | // The RosActivity constructor configures the notification title and
82 | // ticker
83 | // messages.
84 | super("Map nav", "Map nav");
85 | }
86 |
87 | @SuppressWarnings("unchecked")
88 | @Override
89 | public void onCreate(Bundle savedInstanceState) {
90 |
91 | String defaultRobotName = getString(R.string.default_robot);
92 | String defaultAppName = getString(R.string.default_app);
93 | setDefaultMasterName(defaultRobotName);
94 | setDefaultAppName(defaultAppName);
95 | setDashboardResource(R.id.top_bar);
96 | setMainWindowResource(R.layout.main);
97 | super.onCreate(savedInstanceState);
98 |
99 | cameraView = (RosImageView) findViewById(R.id.image);
100 | cameraView.setMessageType(sensor_msgs.CompressedImage._TYPE);
101 | cameraView.setMessageToBitmapCallable(new BitmapFromCompressedImage());
102 | virtualJoystickView = (VirtualJoystickView) findViewById(R.id.virtual_joystick);
103 | backButton = (Button) findViewById(R.id.back_button);
104 | chooseMapButton = (Button) findViewById(R.id.choose_map_button);
105 | mapView = (VisualizationView) findViewById(R.id.map_view);
106 | mapView.onCreate(Lists.newArrayList());
107 |
108 | backButton.setOnClickListener(new View.OnClickListener() {
109 | @Override
110 | public void onClick(View view) {
111 | onBackPressed();
112 | }
113 | });
114 | chooseMapButton.setOnClickListener(new View.OnClickListener() {
115 | @Override
116 | public void onClick(View view) {
117 | onChooseMapButtonPressed();
118 | }
119 | });
120 |
121 | mapView.getCamera().jumpToFrame((String) params.get("map_frame", getString(R.string.map_frame)));
122 | mainLayout = (ViewGroup) findViewById(R.id.main_layout);
123 | sideLayout = (ViewGroup) findViewById(R.id.side_layout);
124 |
125 | }
126 |
127 | @Override
128 | protected void init(NodeMainExecutor nodeMainExecutor) {
129 |
130 | super.init(nodeMainExecutor);
131 |
132 | this.nodeMainExecutor = nodeMainExecutor;
133 | nodeConfiguration = NodeConfiguration.newPublic(InetAddressFactory
134 | .newNonLoopback().getHostAddress(), getMasterUri());
135 |
136 | String joyTopic = remaps.get(getString(R.string.joystick_topic));
137 | String camTopic = remaps.get(getString(R.string.camera_topic));
138 |
139 | NameResolver appNameSpace = getMasterNameSpace();
140 | cameraView.setTopicName(appNameSpace.resolve(camTopic).toString());
141 | virtualJoystickView.setTopicName(appNameSpace.resolve(joyTopic).toString());
142 |
143 | nodeMainExecutor.execute(cameraView,
144 | nodeConfiguration.setNodeName("android/camera_view"));
145 | nodeMainExecutor.execute(virtualJoystickView,
146 | nodeConfiguration.setNodeName("android/virtual_joystick"));
147 |
148 | com.github.rosjava.android_apps.map_nav.ViewControlLayer viewControlLayer =
149 | new com.github.rosjava.android_apps.map_nav.ViewControlLayer(this,
150 | nodeMainExecutor.getScheduledExecutorService(), cameraView,
151 | mapView, mainLayout, sideLayout, params);
152 |
153 | String mapTopic = remaps.get(getString(R.string.map_topic));
154 | String costmapTopic = remaps.get(getString(R.string.costmap_topic));
155 | String scanTopic = remaps.get(getString(R.string.scan_topic));
156 | String planTopic = remaps.get(getString(R.string.global_plan_topic));
157 | String initTopic = remaps.get(getString(R.string.initial_pose_topic));
158 | String robotFrame = (String) params.get("robot_frame", getString(R.string.robot_frame));
159 |
160 | OccupancyGridLayer mapLayer = new OccupancyGridLayer(appNameSpace.resolve(mapTopic).toString());
161 | OccupancyGridLayer costmapLayer = new OccupancyGridLayer(appNameSpace.resolve(costmapTopic).toString());
162 | LaserScanLayer laserScanLayer = new LaserScanLayer(appNameSpace.resolve(scanTopic).toString());
163 | PathLayer pathLayer = new PathLayer(appNameSpace.resolve(planTopic).toString());
164 | mapPosePublisherLayer = new com.github.rosjava.android_apps.map_nav.MapPosePublisherLayer(this, appNameSpace, params, remaps);
165 | com.github.rosjava.android_apps.map_nav.InitialPoseSubscriberLayer initialPoseSubscriberLayer =
166 | new com.github.rosjava.android_apps.map_nav.InitialPoseSubscriberLayer(appNameSpace.resolve(initTopic).toString(), robotFrame);
167 |
168 | mapView.addLayer(viewControlLayer);
169 | mapView.addLayer(mapLayer);
170 | mapView.addLayer(costmapLayer);
171 | mapView.addLayer(laserScanLayer);
172 | mapView.addLayer(pathLayer);
173 | mapView.addLayer(mapPosePublisherLayer);
174 | mapView.addLayer(initialPoseSubscriberLayer);
175 |
176 | mapView.init(nodeMainExecutor);
177 | viewControlLayer.addListener(new CameraControlListener() {
178 | @Override
179 | public void onZoom(float focusX, float focusY, float factor) {}
180 | @Override
181 | public void onDoubleTap(float x, float y) {}
182 | @Override
183 | public void onTranslate(float distanceX, float distanceY) {}
184 | @Override
185 | public void onRotate(float focusX, float focusY, double deltaAngle) {}
186 | });
187 |
188 | TimeProvider timeProvider = null;
189 | try {
190 | NtpTimeProvider ntpTimeProvider = new NtpTimeProvider(
191 | InetAddressFactory.newFromHostString("pool.ntp.org"),
192 | nodeMainExecutor.getScheduledExecutorService());
193 | ntpTimeProvider.startPeriodicUpdates(1, TimeUnit.MINUTES);
194 | timeProvider = ntpTimeProvider;
195 | } catch (Throwable t) {
196 | Log.w(TAG, "Unable to use NTP provider, using Wall Time. Error: " + t.getMessage(), t);
197 | timeProvider = new WallTimeProvider();
198 | }
199 | nodeConfiguration.setTimeProvider(timeProvider);
200 | nodeMainExecutor.execute(mapView, nodeConfiguration.setNodeName("android/map_view"));
201 | }
202 |
203 | private void onChooseMapButtonPressed() {
204 | readAvailableMapList();
205 | }
206 |
207 | public void setPoseClicked(View view) {
208 | setPose();
209 | }
210 |
211 | public void setGoalClicked(View view) {
212 | setGoal();
213 | }
214 |
215 | private void setPose() {
216 | mapPosePublisherLayer.setPoseMode();
217 | }
218 |
219 | private void setGoal() {
220 | mapPosePublisherLayer.setGoalMode();
221 | }
222 |
223 | private void readAvailableMapList() {
224 | safeShowWaitingDialog("Waiting...", "Waiting for map list");
225 |
226 | com.github.rosjava.android_apps.map_nav.MapManager mapManager = new com.github.rosjava.android_apps.map_nav.MapManager(this, remaps);
227 | mapManager.setNameResolver(getMasterNameSpace());
228 | mapManager.setFunction("list");
229 | safeShowWaitingDialog("Waiting...", "Waiting for map list");
230 | mapManager.setListService(new ServiceResponseListener() {
231 | @Override
232 | public void onSuccess(ListMapsResponse message) {
233 | Log.i(TAG, "readAvailableMapList() Success");
234 | safeDismissWaitingDialog();
235 | showMapListDialog(message.getMapList());
236 | }
237 |
238 | @Override
239 | public void onFailure(RemoteException e) {
240 | Log.i(TAG, "readAvailableMapList() Failure");
241 | safeDismissWaitingDialog();
242 | }
243 | });
244 |
245 | nodeMainExecutor.execute(mapManager,
246 | nodeConfiguration.setNodeName("android/list_maps"));
247 | }
248 |
249 | /**
250 | * Show a dialog with a list of maps. Safe to call from any thread.
251 | */
252 | private void showMapListDialog(final List list) {
253 | // Make an array of map name/date strings.
254 | final CharSequence[] availableMapNames = new CharSequence[list.size()];
255 | for (int i = 0; i < list.size(); i++) {
256 | String displayString;
257 | String name = list.get(i).getName();
258 | Date creationDate = new Date(list.get(i).getDate() * 1000);
259 | String dateTime = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
260 | DateFormat.SHORT).format(creationDate);
261 | if (name != null && !name.equals("")) {
262 | displayString = name + " " + dateTime;
263 | } else {
264 | displayString = dateTime;
265 | }
266 | availableMapNames[i] = displayString;
267 | }
268 |
269 | runOnUiThread(new Runnable() {
270 | @Override
271 | public void run() {
272 | AlertDialog.Builder builder = new AlertDialog.Builder(
273 | MainActivity.this);
274 | builder.setTitle("Choose a map");
275 | builder.setItems(availableMapNames,
276 | new DialogInterface.OnClickListener() {
277 | @Override
278 | public void onClick(DialogInterface dialog,
279 | int itemIndex) {
280 | loadMap(list.get(itemIndex));
281 | }
282 | });
283 | chooseMapDialog = builder.create();
284 | chooseMapDialog.show();
285 | }
286 | });
287 | }
288 |
289 | private void loadMap(MapListEntry mapListEntry) {
290 |
291 | com.github.rosjava.android_apps.map_nav.MapManager mapManager = new com.github.rosjava.android_apps.map_nav.MapManager(this, remaps);
292 | mapManager.setNameResolver(getMasterNameSpace());
293 | mapManager.setFunction("publish");
294 | mapManager.setMapId(mapListEntry.getMapId());
295 |
296 | safeShowWaitingDialog("Waiting...", "Loading map");
297 | try {
298 | mapManager
299 | .setPublishService(new ServiceResponseListener() {
300 | @Override
301 | public void onSuccess(PublishMapResponse message) {
302 | Log.i(TAG, "loadMap() Success");
303 | safeDismissWaitingDialog();
304 | // poseSetter.enable();
305 | }
306 |
307 | @Override
308 | public void onFailure(RemoteException e) {
309 | Log.i(TAG, "loadMap() Failure");
310 | safeDismissWaitingDialog();
311 | }
312 | });
313 | } catch (Throwable ex) {
314 | Log.e(TAG, "loadMap() caught exception.", ex);
315 | safeDismissWaitingDialog();
316 | }
317 | nodeMainExecutor.execute(mapManager,
318 | nodeConfiguration.setNodeName("android/publish_map"));
319 | }
320 |
321 | private void safeDismissChooseMapDialog() {
322 | runOnUiThread(new Runnable() {
323 | @Override
324 | public void run() {
325 | if (chooseMapDialog != null) {
326 | chooseMapDialog.dismiss();
327 | chooseMapDialog = null;
328 | }
329 | }
330 | });
331 | }
332 |
333 | private void showWaitingDialog(final CharSequence title,
334 | final CharSequence message) {
335 | dismissWaitingDialog();
336 | waitingDialog = ProgressDialog.show(MainActivity.this, title, message,
337 | true);
338 | waitingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
339 | }
340 |
341 | private void dismissWaitingDialog() {
342 | if (waitingDialog != null) {
343 | waitingDialog.dismiss();
344 | waitingDialog = null;
345 | }
346 | }
347 |
348 | private void safeShowWaitingDialog(final CharSequence title,
349 | final CharSequence message) {
350 | runOnUiThread(new Runnable() {
351 | @Override
352 | public void run() {
353 | showWaitingDialog(title, message);
354 | }
355 | });
356 | }
357 |
358 | private void safeDismissWaitingDialog() {
359 | runOnUiThread(new Runnable() {
360 | @Override
361 | public void run() {
362 | dismissWaitingDialog();
363 | }
364 | });
365 | }
366 |
367 | @Override
368 | public boolean onCreateOptionsMenu(Menu menu) {
369 | menu.add(0, 0, 0, R.string.stop_app);
370 | return super.onCreateOptionsMenu(menu);
371 | }
372 |
373 | @Override
374 | public boolean onOptionsItemSelected(MenuItem item) {
375 | super.onOptionsItemSelected(item);
376 | switch (item.getItemId()) {
377 | case 0:
378 | onDestroy();
379 | break;
380 | }
381 | return true;
382 | }
383 | }
--------------------------------------------------------------------------------
/map_manager/src/main/java/com/github/rosjava/android_apps/map_manager/MainActivity.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2013 OSRF.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package com.github.rosjava.android_apps.map_manager;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.app.AlertDialog;
21 | import android.app.Dialog;
22 | import android.app.ProgressDialog;
23 | import android.content.DialogInterface;
24 | import android.os.Bundle;
25 | import android.util.Log;
26 | import android.view.Display;
27 | import android.view.KeyEvent;
28 | import android.view.Menu;
29 | import android.view.MenuItem;
30 | import android.view.MotionEvent;
31 | import android.view.View;
32 | import android.view.View.OnLongClickListener;
33 | import android.view.View.OnTouchListener;
34 | import android.view.WindowManager;
35 | import android.widget.Button;
36 | import android.widget.EditText;
37 | import android.widget.ListView;
38 |
39 | import com.github.rosjava.android_remocons.common_tools.apps.RosAppActivity;
40 | import com.google.common.collect.Lists;
41 |
42 | import org.ros.address.InetAddressFactory;
43 | import org.ros.android.view.visualization.VisualizationView;
44 | import org.ros.android.view.visualization.layer.CameraControlLayer;
45 | import org.ros.android.view.visualization.layer.CameraControlListener;
46 | import org.ros.android.view.visualization.layer.Layer;
47 | import org.ros.android.view.visualization.layer.OccupancyGridLayer;
48 | import org.ros.exception.RemoteException;
49 | import org.ros.namespace.NameResolver;
50 | import org.ros.node.NodeConfiguration;
51 | import org.ros.node.NodeMainExecutor;
52 | import org.ros.node.service.ServiceResponseListener;
53 |
54 | import java.text.DateFormat;
55 | import java.util.ArrayList;
56 | import java.util.Date;
57 | import java.util.List;
58 |
59 | import world_canvas_msgs.DeleteMapResponse;
60 | import world_canvas_msgs.ListMapsResponse;
61 | import world_canvas_msgs.MapListEntry;
62 | import world_canvas_msgs.PublishMapResponse;
63 | import world_canvas_msgs.RenameMapResponse;
64 |
65 | /**
66 | * @author murase@jsk.imi.i.u-tokyo.ac.jp (Kazuto Murase)
67 | */
68 | @SuppressLint("NewApi")
69 | public class MainActivity extends RosAppActivity {
70 |
71 | private static final int NAME_MAP_DIALOG_ID = 0;
72 |
73 | private NodeConfiguration nodeConfiguration;
74 | private NodeMainExecutor nodeMainExecutor;
75 |
76 | private VisualizationView mapView;
77 | private Button backButton;
78 | private Button renameButton;
79 | private ListView mapListView;
80 | private ArrayList mapList = new ArrayList();
81 | public OnTouchListener gestureListener;
82 | public OnLongClickListener longClickListener;
83 | private int radioFocus = 0;
84 | private int viewPosition = -1;
85 | private int targetPosition;
86 | private boolean startMapManager = true;
87 | private boolean showDeleteDialog = false;
88 | private boolean visibleMapView = true;
89 | private ProgressDialog waitingDialog;
90 | private AlertDialog errorDialog;
91 | private CameraControlLayer cameraControlLayer;
92 | private OccupancyGridLayer occupancyGridLayer;
93 |
94 | public MainActivity() {
95 | // The RosActivity constructor configures the notification title and
96 | // ticker
97 | // messages.
98 | super("map manager", "map manager");
99 | }
100 |
101 | @SuppressWarnings("unchecked")
102 | @Override
103 | public void onCreate(Bundle savedInstanceState) {
104 |
105 | String defaultRobotName = getString(R.string.default_robot);
106 | String defaultAppName = getString(R.string.default_app);
107 | setDefaultMasterName(defaultRobotName);
108 | setDefaultAppName(defaultAppName);
109 | setDashboardResource(R.id.top_bar);
110 | setMainWindowResource(R.layout.main);
111 | super.onCreate(savedInstanceState);
112 |
113 | WindowManager windowManager = getWindowManager();
114 | final Display display = windowManager.getDefaultDisplay();
115 |
116 | mapListView = (ListView) findViewById(R.id.map_list);
117 | mapView = (VisualizationView) findViewById(R.id.map_view);
118 | backButton = (Button) findViewById(R.id.back_button);
119 | renameButton = (Button) findViewById(R.id.rename_button);
120 | cameraControlLayer = new CameraControlLayer();
121 | mapView.onCreate(Lists.newArrayList(cameraControlLayer));
122 |
123 | backButton.setOnClickListener(new View.OnClickListener() {
124 | @Override
125 | public void onClick(View view) {
126 | onBackPressed();
127 | }
128 | });
129 |
130 | renameButton.setOnClickListener(new View.OnClickListener() {
131 | @Override
132 | public void onClick(View view) {
133 | if (radioFocus != -1) {
134 | targetPosition = radioFocus;
135 | showDialog(NAME_MAP_DIALOG_ID);
136 | }
137 | }
138 | });
139 |
140 | gestureListener = new View.OnTouchListener() {
141 | private int padding = 0;
142 | private int initialX = 0;
143 | private int currentX = 0;
144 |
145 | public boolean onTouch(View v, MotionEvent event) {
146 | if (!showDeleteDialog) {
147 |
148 | if (event.getAction() == MotionEvent.ACTION_DOWN) {
149 | padding = 0;
150 | initialX = (int) event.getX();
151 | currentX = (int) event.getX();
152 | }
153 | if (event.getAction() == MotionEvent.ACTION_MOVE) {
154 | currentX = (int) event.getX();
155 | padding = currentX - initialX;
156 | }
157 |
158 | if (event.getAction() == MotionEvent.ACTION_UP
159 | || event.getAction() == MotionEvent.ACTION_CANCEL) {
160 | padding = 0;
161 | initialX = 0;
162 | currentX = 0;
163 | }
164 |
165 | if (Math.abs(padding) > display.getWidth() * 0.2f) {
166 | deleteMap(v.getId());
167 | v.setAlpha(0);
168 | showDeleteDialog = true;
169 | return true;
170 | }
171 | v.setPadding(padding, 0, -padding, 0);
172 | float alpha = 1 - Math.abs(padding)
173 | / (display.getWidth() * 0.2f);
174 | if (alpha > 0) {
175 | v.setAlpha(alpha);
176 |
177 | } else {
178 | v.setAlpha(0);
179 | }
180 | }
181 | return false;
182 | }
183 | };
184 |
185 | longClickListener = new View.OnLongClickListener() {
186 |
187 | @Override
188 | public boolean onLongClick(View v) {
189 | targetPosition = v.getId();
190 | showDialog(NAME_MAP_DIALOG_ID);
191 | return false;
192 | }
193 |
194 | };
195 |
196 |
197 | mapView.getCamera().jumpToFrame((String) params.get("robot_frame", getString(R.string.robot_frame)));
198 | }
199 |
200 | @Override
201 | protected void init(NodeMainExecutor nodeMainExecutor) {
202 |
203 | super.init(nodeMainExecutor);
204 |
205 | this.nodeMainExecutor = nodeMainExecutor;
206 | nodeConfiguration = NodeConfiguration.newPublic(InetAddressFactory
207 | .newNonLoopback().getHostAddress(), getMasterUri());
208 |
209 | NameResolver appNameSpace = getMasterNameSpace();
210 | String mapTopic = remaps.get(getString(R.string.map_topic));
211 |
212 | mapView.init(nodeMainExecutor);
213 | cameraControlLayer.addListener(new CameraControlListener() {
214 | @Override
215 | public void onZoom(float focusX, float focusY, float factor) {}
216 | @Override
217 | public void onDoubleTap(float x, float y) {}
218 | @Override
219 | public void onTranslate(float distanceX, float distanceY) {}
220 | @Override
221 | public void onRotate(float focusX, float focusY, double deltaAngle) {}
222 |
223 | });
224 | occupancyGridLayer = new OccupancyGridLayer(appNameSpace.resolve(mapTopic).toString());
225 | mapView.addLayer(occupancyGridLayer);
226 |
227 | nodeMainExecutor.execute(mapView, nodeConfiguration.setNodeName("android/map_view"));
228 | updateMapList();
229 | }
230 |
231 | protected void updateMapView(int position) {
232 | radioFocus = position;
233 | updateMapView(MainActivity.this.mapList.get(position));
234 | }
235 |
236 | private void updateMapView(MapListEntry map) {
237 |
238 | MapManager mapManager = new MapManager();
239 | mapManager.setNameResolver(getMasterNameSpace());
240 | mapManager.setFunction("publish");
241 | mapManager.setMapId(map.getMapId());
242 | safeShowWaitingDialog("Loading...");
243 |
244 | mapManager.setPublishService(new ServiceResponseListener() {
245 | @Override
246 | public void onFailure(RemoteException e) {
247 | e.printStackTrace();
248 | safeDismissWaitingDialog();
249 | safeShowErrorDialog("Error loading map: " + e.toString());
250 | }
251 | @Override
252 | public void onSuccess(PublishMapResponse message) {
253 | safeDismissWaitingDialog();
254 | // disabling temporarily until testing
255 | // this api got deprecated
256 | // see https://github.com/rosjava/android_apps/issues/42
257 | // if (!visibleMapView) {
258 | // mapView.addLayer(occupancyGridLayer);
259 | // visibleMapView = true;
260 | // }
261 | }
262 | });
263 |
264 | nodeMainExecutor.execute(mapManager,
265 | nodeConfiguration.setNodeName("android/publish_map"));
266 |
267 | }
268 |
269 | private void updateMapListGui(final List list) {
270 |
271 | final ArrayList availableMapNames = new ArrayList();
272 | for (int i = 0; i < list.size(); i++) {
273 | String displayString;
274 | String name = list.get(i).getName();
275 | Date creationDate = new Date(list.get(i).getDate() * 1000);
276 | String dateTime = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
277 | DateFormat.SHORT).format(creationDate);
278 | if (name != null && !name.equals("")) {
279 | displayString = name + " " + dateTime;
280 | } else {
281 | displayString = dateTime;
282 | }
283 | MapListData mapListData = new MapListData();
284 | mapListData.setText(displayString);
285 | if (i == radioFocus) {
286 | mapListData.setChecked(true);
287 | } else
288 | mapListData.setChecked(false);
289 | mapListData.setId(i);
290 | availableMapNames.add(mapListData);
291 | }
292 |
293 | mapList = (ArrayList) list;
294 |
295 | if (startMapManager) {
296 | startMapManager = false;
297 | updateMapView(0);
298 | }
299 |
300 | runOnUiThread(new Runnable() {
301 | @Override
302 | public void run() {
303 | final MapListArrayAdapter ad = new MapListArrayAdapter(
304 | MainActivity.this, 0, availableMapNames,
305 | gestureListener,longClickListener);
306 | mapListView.setAdapter(ad);
307 | if (viewPosition != -1) {
308 | mapListView.setSelection(viewPosition);
309 | }
310 |
311 | }
312 | });
313 | }
314 |
315 | private void updateMapList() {
316 |
317 | MapManager mapManager = new MapManager();
318 | mapManager.setNameResolver(getMasterNameSpace());
319 | mapManager.setFunction("list");
320 | safeShowWaitingDialog("Waiting for maps...");
321 |
322 | mapManager.setListService(new ServiceResponseListener() {
323 | @Override
324 | public void onSuccess(ListMapsResponse message) {
325 | Log.i("MapManager", "readAvailableMapList() Success");
326 | safeDismissWaitingDialog();
327 | updateMapListGui(message.getMapList());
328 | }
329 |
330 | @Override
331 | public void onFailure(RemoteException arg0) {
332 | Log.i("MapManager", "readAvailableMapList() Failure");
333 | safeDismissWaitingDialog();
334 |
335 | }
336 | });
337 |
338 | nodeMainExecutor.execute(mapManager,
339 | nodeConfiguration.setNodeName("android/list_maps"));
340 |
341 | }
342 |
343 | public void deleteMap(int position) {
344 | final String id = mapList.get(position).getMapId();
345 | viewPosition = mapListView.getFirstVisiblePosition();
346 |
347 | if (id == null) {
348 | return;
349 | }
350 | final int radioFocusRelation;
351 | if (position == radioFocus) {
352 | radioFocusRelation = 0;
353 | } else if (position < radioFocus) {
354 | radioFocusRelation = 1;
355 | } else
356 | radioFocusRelation = -1;
357 |
358 | AlertDialog.Builder dialog = new AlertDialog.Builder(this);
359 | dialog.setTitle("Are You Sure?");
360 | dialog.setMessage("Are you sure you want to delete this map?");
361 | dialog.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
362 | @Override
363 | public void onClick(DialogInterface dlog, int i) {
364 | dlog.dismiss();
365 | safeShowWaitingDialog("Deleting...");
366 | try {
367 | MapManager mapManager = new MapManager();
368 | mapManager.setNameResolver(getMasterNameSpace());
369 | mapManager.setFunction("delete");
370 | mapManager.setMapId(id);
371 |
372 | mapManager.setDeleteService(new ServiceResponseListener() {
373 |
374 | @Override
375 | public void onFailure(RemoteException e) {
376 | showDeleteDialog = false;
377 | e.printStackTrace();
378 |
379 | }
380 |
381 | @Override
382 | public void onSuccess(DeleteMapResponse arg0) {
383 |
384 | if (viewPosition != 0) {
385 | viewPosition += 1;
386 | }
387 | switch (radioFocusRelation) {
388 | case 0:
389 | // disabling temporarily until testing
390 | // this api got deprecated
391 | // see https://github.com/rosjava/android_apps/issues/42
392 | //mapView.hideLayer(occupancyGridLayer);
393 | //visibleMapView = false;
394 | radioFocus = -1;
395 | break;
396 | case 1:
397 | radioFocus -= 1;
398 | break;
399 | }
400 | showDeleteDialog = false;
401 |
402 | MainActivity.this
403 | .runOnUiThread(new Runnable() {
404 | public void run() {
405 | safeDismissWaitingDialog();
406 | updateMapList();
407 | }
408 | });
409 | }
410 | });
411 |
412 | nodeMainExecutor.execute(mapManager,
413 | nodeConfiguration.setNodeName("android/delete_map"));
414 |
415 | } catch (Exception e) {
416 | e.printStackTrace();
417 | safeShowErrorDialog("Error during map delete: "
418 | + e.toString());
419 | }
420 | }
421 | });
422 |
423 | dialog.setNegativeButton("No", new DialogInterface.OnClickListener() {
424 | @Override
425 | public void onClick(DialogInterface dlog, int i) {
426 | if (viewPosition != 0) {
427 | viewPosition += 1;
428 | }
429 | showDeleteDialog = false;
430 | updateMapList();
431 | dlog.dismiss();
432 | }
433 | });
434 | dialog.show();
435 | }
436 |
437 | @Override
438 | protected Dialog onCreateDialog(int id) {
439 | Dialog dialog;
440 | Button button;
441 | switch (id) {
442 | case NAME_MAP_DIALOG_ID:
443 | viewPosition = mapListView.getFirstVisiblePosition();
444 | dialog = new Dialog(this);
445 | dialog.setContentView(R.layout.name_map_dialog);
446 | dialog.setTitle("Rename Map");
447 |
448 | final String targetMapId = mapList.get(targetPosition).getMapId();
449 | final EditText nameField = (EditText) dialog
450 | .findViewById(R.id.name_editor);
451 | nameField.setText(mapList.get(targetPosition).getName());
452 | nameField.setOnKeyListener(new View.OnKeyListener() {
453 | @Override
454 | public boolean onKey(final View view, int keyCode,
455 | KeyEvent event) {
456 | if (event.getAction() == KeyEvent.ACTION_DOWN
457 | && keyCode == KeyEvent.KEYCODE_ENTER) {
458 | String newName = nameField.getText().toString();
459 | if (newName != null && newName.length() > 0) {
460 | safeShowWaitingDialog("Waiting for rename...");
461 | try {
462 | MapManager mapManager = new MapManager();
463 | mapManager.setNameResolver(getMasterNameSpace());
464 | mapManager.setFunction("rename");
465 | mapManager.setMapId(targetMapId);
466 | mapManager.setMapName(newName);
467 |
468 | mapManager.setRenameService(
469 | new ServiceResponseListener() {
470 |
471 | @Override
472 | public void onFailure(
473 | RemoteException e) {
474 | e.printStackTrace();
475 | safeShowErrorDialog("Error during rename: "
476 | + e.toString());
477 | }
478 |
479 | @Override
480 | public void onSuccess(
481 | RenameMapResponse arg0) {
482 | MainActivity.this
483 | .runOnUiThread(new Runnable() {
484 | public void run() {
485 | safeDismissWaitingDialog();
486 | updateMapList();
487 | }
488 | });
489 | }
490 | });
491 | nodeMainExecutor.execute(mapManager,
492 | nodeConfiguration
493 | .setNodeName("android/rename_map"));
494 |
495 | } catch (Exception e) {
496 | e.printStackTrace();
497 | safeShowErrorDialog("Error during rename: "
498 | + e.toString());
499 | }
500 | }
501 | removeDialog(NAME_MAP_DIALOG_ID);
502 | return true;
503 | } else {
504 | return false;
505 | }
506 | }
507 | });
508 |
509 | button = (Button) dialog.findViewById(R.id.cancel_button);
510 | button.setOnClickListener(new View.OnClickListener() {
511 | @Override
512 | public void onClick(View v) {
513 | removeDialog(NAME_MAP_DIALOG_ID);
514 | }
515 | });
516 | break;
517 | default:
518 | dialog = null;
519 | }
520 | return dialog;
521 | }
522 |
523 | private void safeShowWaitingDialog(final CharSequence message) {
524 | runOnUiThread(new Runnable() {
525 | @Override
526 | public void run() {
527 | if (waitingDialog != null) {
528 | waitingDialog.dismiss();
529 | waitingDialog = null;
530 | }
531 | waitingDialog = ProgressDialog.show(MainActivity.this, "",
532 | message, true);
533 | }
534 | });
535 | }
536 |
537 | private void safeDismissWaitingDialog() {
538 | runOnUiThread(new Runnable() {
539 | @Override
540 | public void run() {
541 | if (waitingDialog != null) {
542 | waitingDialog.dismiss();
543 | waitingDialog = null;
544 | }
545 | }
546 | });
547 | }
548 |
549 | private void safeShowErrorDialog(final CharSequence message) {
550 | runOnUiThread(new Runnable() {
551 | @Override
552 | public void run() {
553 | if (errorDialog != null) {
554 | errorDialog.dismiss();
555 | errorDialog = null;
556 | }
557 | if (waitingDialog != null) {
558 | waitingDialog.dismiss();
559 | waitingDialog = null;
560 | }
561 | AlertDialog.Builder dialog = new AlertDialog.Builder(
562 | MainActivity.this);
563 | dialog.setTitle("Error");
564 | dialog.setMessage(message);
565 | dialog.setNeutralButton("Ok",
566 | new DialogInterface.OnClickListener() {
567 | @Override
568 | public void onClick(DialogInterface dlog, int i) {
569 | dlog.dismiss();
570 | }
571 | });
572 | errorDialog = dialog.show();
573 | }
574 | });
575 | }
576 |
577 | private void safeDismissErrorDialog() {
578 | runOnUiThread(new Runnable() {
579 | @Override
580 | public void run() {
581 | if (errorDialog != null) {
582 | errorDialog.dismiss();
583 | errorDialog = null;
584 | }
585 | }
586 | });
587 | }
588 |
589 | @Override
590 | public boolean onCreateOptionsMenu(Menu menu) {
591 | menu.add(0, 0, 0, R.string.stop_app);
592 | return super.onCreateOptionsMenu(menu);
593 | }
594 |
595 | @Override
596 | public boolean onOptionsItemSelected(MenuItem item) {
597 | super.onOptionsItemSelected(item);
598 | switch (item.getItemId()) {
599 | case 0:
600 | onDestroy();
601 | break;
602 | }
603 | return true;
604 | }
605 |
606 | }
607 |
--------------------------------------------------------------------------------