1 package com.introlab.rtabmap;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.io.OutputStream;
9 import java.lang.reflect.InvocationTargetException;
10 import java.lang.reflect.Method;
11 import java.text.SimpleDateFormat;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.Date;
15 import java.util.HashMap;
16 import java.util.Timer;
17 import java.util.TimerTask;
19 import android.Manifest;
20 import android.app.ActivityManager;
21 import android.app.ActivityManager.MemoryInfo;
22 import android.app.AlertDialog;
23 import android.app.Notification;
24 import android.app.NotificationManager;
25 import android.app.PendingIntent;
26 import android.app.ProgressDialog;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.DialogInterface;
30 import android.content.DialogInterface.OnShowListener;
31 import android.content.Intent;
32 import android.content.ServiceConnection;
33 import android.content.SharedPreferences;
34 import android.content.pm.ApplicationInfo;
35 import android.content.pm.PackageInfo;
36 import android.content.pm.PackageManager;
37 import android.content.pm.PackageManager.NameNotFoundException;
38 import android.hardware.Camera;
39 import android.hardware.Sensor;
40 import android.hardware.SensorEvent;
41 import android.hardware.SensorEventListener;
42 import android.hardware.SensorManager;
43 import android.graphics.Matrix;
44 import android.graphics.Point;
45 import android.hardware.display.DisplayManager;
46 import android.location.Location;
47 import android.location.LocationListener;
48 import android.location.LocationManager;
49 import android.net.Uri;
50 import android.net.wifi.WifiInfo;
51 import android.net.wifi.WifiManager;
52 import android.opengl.GLSurfaceView;
53 import android.os.Bundle;
54 import android.os.Environment;
55 import android.os.Handler;
56 import android.os.IBinder;
57 import android.os.Message;
58 import android.preference.PreferenceManager;
59 import android.support.v4.app.FragmentActivity;
60 import android.support.v4.content.FileProvider;
61 import android.text.InputType;
62 import android.util.Log;
63 import android.util.TypedValue;
64 import android.view.ContextMenu;
65 import android.view.Display;
66 import android.view.GestureDetector;
67 import android.view.Menu;
68 import android.view.MenuItem;
69 import android.view.MenuItem.OnMenuItemClickListener;
70 import android.view.MenuInflater;
71 import android.view.MotionEvent;
72 import android.view.View;
73 import android.view.ContextMenu.ContextMenuInfo;
74 import android.view.View.OnClickListener;
75 import android.view.View.OnCreateContextMenuListener;
76 import android.view.View.OnTouchListener;
77 import android.view.WindowManager;
78 import android.view.inputmethod.EditorInfo;
79 import android.widget.AdapterView;
80 import android.widget.AdapterView.OnItemSelectedListener;
81 import android.widget.ArrayAdapter;
82 import android.widget.Button;
83 import android.widget.EditText;
84 import android.widget.ImageButton;
85 import android.widget.ListView;
86 import android.widget.NumberPicker;
87 import android.widget.RelativeLayout;
88 import android.widget.SeekBar;
89 import android.widget.SeekBar.OnSeekBarChangeListener;
90 import android.widget.Toast;
91 import android.widget.ToggleButton;
93 import com.google.ar.core.ArCoreApk;
94 import com.google.atap.tangoservice.Tango;
95 import com.huawei.hiar.AREnginesApk;
100 public class RTABMapActivity extends FragmentActivity implements OnClickListener, OnItemSelectedListener, SensorEventListener {
146 STATE_VISUALIZING_WHILE_LOADING
156 int mStatusBarHeight = 0;
157 int mActionBarHeight = 0;
159 ProgressDialog mProgressDialog;
160 ProgressDialog mExportProgressDialog;
223 Sensor mAccelerometer;
224 Sensor mMagnetometer;
225 Sensor mAmbientTemperature;
226 Sensor mAmbientLight;
227 Sensor mAmbientAirPressure;
228 Sensor mAmbientRelativeHumidity;
239 private Matrix
mRMat =
new Matrix();
240 private Matrix
mNewR =
new Matrix();
241 private float[]
mR =
new float[9];
255 GestureDetector mGesDetect = null;
258 int mCameraDriver = 0;
261 boolean mCameraServiceConnectionUsed =
false;
262 ServiceConnection mCameraServiceConnection =
new ServiceConnection() {
263 public void onServiceConnected(ComponentName name,
final IBinder service) {
264 Thread bindThread =
new Thread(
new Runnable() {
267 runOnUiThread(
new Runnable() {
269 mProgressDialog.dismiss();
270 if(!cameraStartSucess)
272 mToast.makeText(getApplicationContext(),
273 String.format(
"Failed to intialize Tango camera! RTAB-Map may not be built with Tango support."), mToast.LENGTH_LONG).show();
274 if(mCameraServiceConnectionUsed)
276 if(!DISABLE_LOG) Log.i(TAG, String.format(
"unbindService"));
277 getActivity().unbindService(mCameraServiceConnection);
279 mCameraServiceConnectionUsed =
false;
296 public void onServiceDisconnected(ComponentName name) {
299 mToast.makeText(getApplicationContext(),
300 String.format(
"Tango disconnected!"), mToast.LENGTH_LONG).show();
305 protected void onCreate(Bundle savedInstanceState) {
306 super.onCreate(savedInstanceState);
307 setTitle(R.string.menu_name);
315 Display display = getWindowManager().getDefaultDisplay();
316 display.getSize(mScreenSize);
318 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
319 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
322 setContentView(R.layout.activity_rtabmap);
327 mDecorView = getWindow().getDecorView();
332 mButtonCameraView = (
NDSpinner)findViewById(R.id.camera_button);
333 mButtonStart = (ImageButton)findViewById(R.id.start_button);
334 mButtonStop = (ImageButton)findViewById(R.id.stop_button);
335 mButtonLighting = (ToggleButton)findViewById(R.id.light_button);
336 mButtonWireframe = (ToggleButton)findViewById(R.id.wireframe_button);
337 mButtonBackfaceShown = (ToggleButton)findViewById(R.id.backface_button);
338 mButtonCloseVisualization = (Button)findViewById(R.id.close_visualization_button);
339 mButtonSaveOnDevice = (Button)findViewById(R.id.button_saveOnDevice);
340 mButtonShareOnSketchfab = (Button)findViewById(R.id.button_shareToSketchfab);
341 mButtonLibrary = (Button)findViewById(R.id.button_library);
342 mButtonNewScan = (Button)findViewById(R.id.button_new_scan);
343 mButtonCameraView.setOnItemSelectedListener(
this);
344 mButtonStart.setOnClickListener(
this);
345 mButtonStop.setOnClickListener(
this);
346 mButtonLighting.setOnClickListener(
this);
347 mButtonWireframe.setOnClickListener(
this);
348 mButtonBackfaceShown.setOnClickListener(
this);
349 mButtonCloseVisualization.setOnClickListener(
this);
350 mButtonSaveOnDevice.setOnClickListener(
this);
351 mButtonShareOnSketchfab.setOnClickListener(
this);
352 mButtonLibrary.setOnClickListener(
this);
353 mButtonNewScan.setOnClickListener(
this);
354 mButtonLighting.setChecked(
false);
355 mButtonLighting.setVisibility(View.INVISIBLE);
356 mButtonWireframe.setChecked(
false);
357 mButtonWireframe.setVisibility(View.INVISIBLE);
358 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
359 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
360 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
361 mButtonLibrary.setVisibility(View.INVISIBLE);
362 mButtonNewScan.setVisibility(View.INVISIBLE);
363 if(mItemRenderingMesh != null && mItemRenderingTextureMesh != null)
365 mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE);
368 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this, R.array.camera_view_array, android.R.layout.simple_spinner_item);
369 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
370 mButtonCameraView.setAdapter(adapter);
371 mButtonCameraView.setOnTouchListener(
new OnTouchListener() {
373 public boolean onTouch(View v, MotionEvent event) {
379 mSeekBarOrthoCut = (SeekBar)findViewById(R.id.seekBar_ortho_cut);
380 mSeekBarOrthoCut.setMax(120);
381 mSeekBarOrthoCut.setProgress(80);
382 mSeekBarOrthoCut.setOnSeekBarChangeListener(
new OnSeekBarChangeListener() {
384 public void onProgressChanged(SeekBar seekBar,
int progressValue,
boolean fromUser) {
390 public void onStartTrackingTouch(SeekBar seekBar) {
394 public void onStopTrackingTouch(SeekBar seekBar) {
398 mSeekBarGrid = (SeekBar)findViewById(R.id.seekBar_grid);
399 mSeekBarGrid.setMax(180);
400 mSeekBarGrid.setProgress(90);
401 mSeekBarGrid.setOnSeekBarChangeListener(
new OnSeekBarChangeListener() {
403 public void onProgressChanged(SeekBar seekBar,
int progressValue,
boolean fromUser) {
409 public void onStartTrackingTouch(SeekBar seekBar) {
413 public void onStopTrackingTouch(SeekBar seekBar) {
417 mToast = Toast.makeText(getApplicationContext(),
"", Toast.LENGTH_SHORT);
420 mGLView = (GLSurfaceView) findViewById(R.id.gl_surface_view);
422 mGesDetect =
new GestureDetector(
this,
new DoubleTapGestureDetector());
425 mGLView.setEGLContextClientVersion(2);
426 mGLView.setEGLConfigChooser(8, 8, 8, 8, 24, 0);
427 mGLView.setOnTouchListener(
new OnTouchListener() {
429 public boolean onTouch(View v, MotionEvent event) {
433 mGesDetect.onTouchEvent(event);
438 int pointCount =
event.getPointerCount();
439 if (pointCount == 1) {
440 float normalizedX =
event.getX(0) / mScreenSize.x;
441 float normalizedY =
event.getY(0) / mScreenSize.y;
443 event.getActionMasked(), normalizedX, normalizedY, 0.0f, 0.0f);
445 if (pointCount == 2) {
446 if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
447 int index =
event.getActionIndex() == 0 ? 1 : 0;
448 float normalizedX =
event.getX(index) / mScreenSize.x;
449 float normalizedY =
event.getY(index) / mScreenSize.y;
451 MotionEvent.ACTION_DOWN, normalizedX, normalizedY, 0.0f, 0.0f);
453 float normalizedX0 =
event.getX(0) / mScreenSize.x;
454 float normalizedY0 =
event.getY(0) / mScreenSize.y;
455 float normalizedX1 =
event.getX(1) / mScreenSize.x;
456 float normalizedY1 =
event.getY(1) / mScreenSize.y;
458 normalizedX0, normalizedY0, normalizedX1, normalizedY1);
467 mGLView.setRenderer(mRenderer);
469 mProgressDialog =
new ProgressDialog(
this);
470 mProgressDialog.setCanceledOnTouchOutside(
false);
475 mExportProgressDialog =
new ProgressDialog(
this);
476 mExportProgressDialog.setCanceledOnTouchOutside(
false);
477 mExportProgressDialog.setCancelable(
false);
478 mExportProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
479 mExportProgressDialog.setProgressNumberFormat(null);
480 mExportProgressDialog.setProgressPercentFormat(null);
481 mExportProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
"Cancel",
new DialogInterface.OnClickListener() {
483 public void onClick(DialogInterface dialog,
int which) {
486 mProgressDialog.setTitle(
"");
487 mProgressDialog.setMessage(String.format(
"Cancelling..."));
488 mProgressDialog.show();
492 mOpenedDatabasePath =
"";
493 mWorkingDirectory =
"";
494 mWorkingDirectoryHuman =
"";
495 mTotalLoopClosures = 0;
496 mLastFastMovementNotificationStamp = System.currentTimeMillis()/1000;
498 if(Environment.getExternalStorageState().compareTo(Environment.MEDIA_MOUNTED)==0)
500 File extStore = Environment.getExternalStorageDirectory();
501 mWorkingDirectory = extStore.getAbsolutePath() +
"/" + getString(R.string.app_name) +
"/";
502 extStore =
new File(mWorkingDirectory);
504 mWorkingDirectoryHuman = RTABMAP_SDCARD_PATH + getString(R.string.app_name) +
"/";
509 mToast.makeText(getApplicationContext(),
510 String.format(
"Failed to get external storage path (SD-CARD, state=%s). Saving disabled.",
511 Environment.getExternalStorageState()), mToast.LENGTH_LONG).show();
514 DisplayManager displayManager = (DisplayManager) getSystemService(DISPLAY_SERVICE);
515 if (displayManager != null) {
516 displayManager.registerDisplayListener(
new DisplayManager.DisplayListener() {
518 public void onDisplayAdded(
int displayId) {
523 public void onDisplayChanged(
int displayId) {
524 synchronized (
this) {
526 Display display = getWindowManager().getDefaultDisplay();
527 display.getSize(mScreenSize);
532 public void onDisplayRemoved(
int displayId) {}
537 mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
540 mLocationListener =
new LocationListener() {
541 public void onLocationChanged(Location location) {
542 mLastKnownLocation = location;
543 double stamp = location.getTime()/1000.0;
544 if(!DISABLE_LOG) Log.d(TAG, String.format(
"GPS received at %f (%d)", stamp, location.getTime()));
548 (
double)location.getLongitude(),
549 (double)location.getLatitude(),
550 (double)location.getAltitude(),
551 (double)location.getAccuracy(),
552 (double)mCompassDeg);
555 public void onStatusChanged(String provider,
int status, Bundle extras) {}
557 public void onProviderEnabled(String provider) {}
559 public void onProviderDisabled(String provider) {}
562 mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
563 mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
564 mMagnetometer = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
565 mAmbientTemperature = mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
566 mAmbientLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
567 mAmbientAirPressure = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
568 mAmbientRelativeHumidity = mSensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY);
569 float [] values = {1,0,0,0,0,1,0,-1,0};
570 mDeviceToCamera.setValues(values);
571 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
575 DISABLE_LOG = !( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
585 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
586 String cameraDriverStr = sharedPref.getString(getString(R.string.pref_key_camera_driver), getString(R.string.pref_default_camera_driver));
587 mCameraDriver = Integer.parseInt(cameraDriverStr);
596 Log.i(TAG,
"postCreate()");
599 (
new File(tmpDatabase)).
delete();
600 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
601 boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory),
Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
605 if(files.length == 0)
607 mButtonLibrary.setVisibility(View.INVISIBLE);
613 Log.i(TAG, String.format(
"updateCameraDriverSettings() mCameraDriver=%d RTABMapLib.isBuiltWith(%d)=%d", mCameraDriver, mCameraDriver,
RTABMapLib.
isBuiltWith(nativeApplication, mCameraDriver)?1:0));
615 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
621 SharedPreferences.Editor editor = sharedPref.edit();
622 editor.putString(getString(R.string.pref_key_camera_driver),
"2");
625 else if(mIsARCoreAvailable)
627 SharedPreferences.Editor editor = sharedPref.edit();
628 editor.putString(getString(R.string.pref_key_camera_driver),
"3");
637 SharedPreferences.Editor editor = sharedPref.edit();
638 editor.putString(getString(R.string.pref_key_camera_driver),
"0");
643 SharedPreferences.Editor editor = sharedPref.edit();
644 editor.putString(getString(R.string.pref_key_camera_driver),
"2");
648 else if(mCameraDriver == 2 && (!mIsAREngineAvailable || !
RTABMapLib.
isBuiltWith(nativeApplication, 2)))
652 SharedPreferences.Editor editor = sharedPref.edit();
653 editor.putString(getString(R.string.pref_key_camera_driver),
"0");
656 else if(mIsARCoreAvailable)
658 SharedPreferences.Editor editor = sharedPref.edit();
659 editor.putString(getString(R.string.pref_key_camera_driver),
"3");
666 ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(
this);
667 if (availability.isTransient()) {
669 new Handler().postDelayed(
new Runnable() {
676 if (availability.isSupported()) {
677 Log.i(TAG,
"ARCore supported");
678 mIsARCoreAvailable =
true;
681 Log.i(TAG,
"ARCore supported");
682 mIsARCoreAvailable =
false;
689 AREnginesApk.ARAvailability availability = AREnginesApk.checkAvailability(
this);
690 if (availability.isTransient()) {
692 new Handler().postDelayed(
new Runnable() {
699 if (availability.isSupported()) {
700 Log.i(TAG,
"AREngine supported");
701 mIsAREngineAvailable =
true;
704 Log.i(TAG,
"AREngine not supported");
705 mIsAREngineAvailable =
false;
709 catch(UnsatisfiedLinkError
e)
711 Log.i(TAG,
"AREngine not supported");
712 mIsAREngineAvailable =
false;
721 if(!DISABLE_LOG) Log.d(TAG,
"onDestroy()");
723 synchronized (
this) {
725 nativeApplication = 0;
731 if(event.sensor == mAccelerometer || event.sensor == mMagnetometer)
733 if (event.sensor == mAccelerometer) {
734 System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
735 mLastAccelerometerSet =
true;
736 }
else if (event.sensor == mMagnetometer) {
737 System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
738 mLastMagnetometerSet =
true;
740 if (mLastAccelerometerSet && mLastMagnetometerSet) {
741 SensorManager.getRotationMatrix(mR, null, mLastAccelerometer, mLastMagnetometer);
743 mNewR.setConcat(mRMat, mDeviceToCamera) ;
745 SensorManager.getOrientation(mR, mOrientation);
746 mCompassDeg = mOrientation[0] * 180.0f/(float)Math.PI;
749 mCompassDeg += 360.0f;
753 else if(event.sensor == mAmbientTemperature)
755 mLastEnvSensors[1] =
event.values[0];
756 mLastEnvSensorsSet[1] =
true;
759 else if(event.sensor == mAmbientAirPressure)
761 mLastEnvSensors[2] =
event.values[0];
762 mLastEnvSensorsSet[2] =
true;
765 else if(event.sensor == mAmbientLight)
767 mLastEnvSensors[3] =
event.values[0];
768 mLastEnvSensorsSet[3] =
true;
771 else if(event.sensor == mAmbientRelativeHumidity)
773 mLastEnvSensors[4] =
event.values[0];
774 mLastEnvSensorsSet[4] =
true;
787 int resourceId = getResources().getIdentifier(
"status_bar_height",
"dimen",
"android");
788 if (resourceId > 0) {
789 result = getResources().getDimensionPixelSize(resourceId);
795 TypedValue tv =
new TypedValue();
796 if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv,
true))
798 result = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
807 super.onWindowFocusChanged(hasFocus);
811 mRenderer.
setOffset(!hasFocus?-mStatusBarHeight:0);
817 int newVis = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
818 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
819 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
821 newVis |= View.SYSTEM_UI_FLAG_LOW_PROFILE
822 | View.SYSTEM_UI_FLAG_FULLSCREEN
823 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
824 | View.SYSTEM_UI_FLAG_IMMERSIVE;
825 mRenderer.
setOffset(!hasWindowFocus()?-mStatusBarHeight:0);
829 mRenderer.
setOffset(-mStatusBarHeight-mActionBarHeight);
833 mDecorView.setSystemUiVisibility(newVis);
839 if (requestCode == Tango.TANGO_INTENT_ACTIVITYCODE) {
841 if (resultCode == RESULT_CANCELED) {
842 mToast.makeText(
this,
"Motion Tracking Permissions Required!", mToast.LENGTH_SHORT).show();
845 else if (requestCode == SKETCHFAB_ACTIVITY_CODE) {
847 if (resultCode == RESULT_OK) {
848 mAuthToken = data.getStringExtra(RTABMAP_AUTH_TOKEN_KEY);
856 return super.onMenuOpened(featureId, menu);
868 boolean doubleBack = t.getTime() - mBackClickedTime.getTime() < 3500;
869 mBackClickedTime = t;
882 super.onBackPressed();
886 mToast.makeText(
this,
"Press Back once more to exit", mToast.LENGTH_LONG).show();
902 if(!DISABLE_LOG) Log.i(TAG,
"onPause()");
914 mLocationManager.removeUpdates(mLocationListener);
915 mSensorManager.unregisterListener(
this);
916 mLastAccelerometerSet =
false;
917 mLastMagnetometerSet=
false;
918 mLastEnvSensorsSet[0] = mLastEnvSensorsSet[1]= mLastEnvSensorsSet[2]= mLastEnvSensorsSet[3]= mLastEnvSensorsSet[4]=
false;
923 mOnPauseStamp = System.currentTimeMillis()/1000;
931 Log.i(TAG,
"update preferences...");
932 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
933 mUpdateRate = sharedPref.getString(getString(R.string.pref_key_update_rate), getString(R.string.pref_default_update_rate));
934 String maxSpeed = sharedPref.getString(getString(R.string.pref_key_max_speed), getString(R.string.pref_default_max_speed));
935 mTimeThr = sharedPref.getString(getString(R.string.pref_key_time_thr), getString(R.string.pref_default_time_thr));
936 String memThr = sharedPref.getString(getString(R.string.pref_key_mem_thr), getString(R.string.pref_default_mem_thr));
937 mLoopThr = sharedPref.getString(getString(R.string.pref_key_loop_thr), getString(R.string.pref_default_loop_thr));
938 String simThr = sharedPref.getString(getString(R.string.pref_key_sim_thr), getString(R.string.pref_default_sim_thr));
939 mMinInliers = sharedPref.getString(getString(R.string.pref_key_min_inliers), getString(R.string.pref_default_min_inliers));
940 mMaxOptimizationError = sharedPref.getString(getString(R.string.pref_key_opt_error), getString(R.string.pref_default_opt_error));
941 float maxOptimizationError = Float.parseFloat(mMaxOptimizationError);
942 if(maxOptimizationError >0 && maxOptimizationError<1)
944 Log.w(TAG,
"Migration of " + getString(R.string.pref_key_opt_error) +
" from " + mMaxOptimizationError +
" to " + getString(R.string.pref_default_opt_error)) ;
945 SharedPreferences.Editor editor = sharedPref.edit();
946 editor.putString(getString(R.string.pref_key_opt_error), getString(R.string.pref_default_opt_error));
948 mMaxOptimizationError = getString(R.string.pref_default_opt_error);
950 mMaxFeatures = sharedPref.getString(getString(R.string.pref_key_features_voc), getString(R.string.pref_default_features_voc));
951 String maxFeaturesLoop = sharedPref.getString(getString(R.string.pref_key_features), getString(R.string.pref_default_features));
952 String featureType = sharedPref.getString(getString(R.string.pref_key_features_type), getString(R.string.pref_default_features_type));
953 boolean keepAllDb = sharedPref.getBoolean(getString(R.string.pref_key_keep_all_db),
Boolean.parseBoolean(getString(R.string.pref_default_keep_all_db)));
954 boolean optimizeFromGraphEnd = sharedPref.getBoolean(getString(R.string.pref_key_optimize_end),
Boolean.parseBoolean(getString(R.string.pref_default_optimize_end)));
955 String optimizer = sharedPref.getString(getString(R.string.pref_key_optimizer), getString(R.string.pref_default_optimizer));
956 String markerDetection = sharedPref.getString(getString(R.string.pref_key_marker_detection), getString(R.string.pref_default_marker_detection));
957 String markerDetectionDepthError = sharedPref.getString(getString(R.string.pref_key_marker_detection_depth_error), getString(R.string.pref_default_marker_detection_depth_error));
958 mGPSSaved =
PermissionHelper.
hasPermission(
this, Manifest.permission.ACCESS_FINE_LOCATION) && sharedPref.getBoolean(getString(R.string.pref_key_gps_saved),
Boolean.parseBoolean(getString(R.string.pref_default_gps_saved)));
961 mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListener);
962 mSensorManager.registerListener(
this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
963 mSensorManager.registerListener(
this, mMagnetometer, SensorManager.SENSOR_DELAY_UI);
965 mEnvSensorsSaved = sharedPref.getBoolean(getString(R.string.pref_key_env_sensors_saved),
Boolean.parseBoolean(getString(R.string.pref_default_env_sensors_saved)));
968 mSensorManager.registerListener(
this, mAmbientTemperature, SensorManager.SENSOR_DELAY_NORMAL);
969 mSensorManager.registerListener(
this, mAmbientAirPressure, SensorManager.SENSOR_DELAY_NORMAL);
970 mSensorManager.registerListener(
this, mAmbientLight, SensorManager.SENSOR_DELAY_NORMAL);
971 mSensorManager.registerListener(
this, mAmbientRelativeHumidity, SensorManager.SENSOR_DELAY_NORMAL);
972 mEnvSensorsTimer.schedule(
new TimerTask() {
976 WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
978 if(wifiInfo != null && (dbm = wifiInfo.getRssi()) > -127)
980 mLastEnvSensors[0] = (float)dbm;
981 mLastEnvSensorsSet[0] =
true;
989 Log.i(TAG,
"set mapping parameters");
990 RTABMapLib.
setOnlineBlending(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_blending),
Boolean.parseBoolean(getString(R.string.pref_default_blending))));
991 RTABMapLib.
setNodesFiltering(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_nodes_filtering),
Boolean.parseBoolean(getString(R.string.pref_default_nodes_filtering))));
992 RTABMapLib.
setRawScanSaved(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_raw_scan_saved),
Boolean.parseBoolean(getString(R.string.pref_default_raw_scan_saved))));
993 RTABMapLib.
setFullResolution(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_resolution),
Boolean.parseBoolean(getString(R.string.pref_default_resolution))));
994 RTABMapLib.
setSmoothing(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_smoothing),
Boolean.parseBoolean(getString(R.string.pref_default_smoothing))));
995 RTABMapLib.
setDepthFromMotion(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_depth_from_motion),
Boolean.parseBoolean(getString(R.string.pref_default_depth_from_motion))));
996 RTABMapLib.
setCameraColor(nativeApplication, !sharedPref.getBoolean(getString(R.string.pref_key_fisheye),
Boolean.parseBoolean(getString(R.string.pref_default_fisheye))));
997 RTABMapLib.
setAppendMode(nativeApplication, sharedPref.getBoolean(getString(R.string.pref_key_append),
Boolean.parseBoolean(getString(R.string.pref_default_append))));
1014 if(Integer.parseInt(markerDetection) == -1)
1026 Log.i(TAG,
"set exporting parameters...");
1027 RTABMapLib.
setCloudDensityLevel(nativeApplication, Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_density), getString(R.string.pref_default_density))));
1028 RTABMapLib.
setMaxCloudDepth(nativeApplication, Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_depth), getString(R.string.pref_default_depth))));
1029 RTABMapLib.
setMinCloudDepth(nativeApplication, Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_min_depth), getString(R.string.pref_default_min_depth))));
1030 RTABMapLib.
setPointSize(nativeApplication, Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_point_size), getString(R.string.pref_default_point_size))));
1031 RTABMapLib.
setMeshAngleTolerance(nativeApplication, Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_angle), getString(R.string.pref_default_angle))));
1032 RTABMapLib.
setMeshTriangleSize(nativeApplication, Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_triangle), getString(R.string.pref_default_triangle))));
1033 float bgColor = Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_background_color), getString(R.string.pref_default_background_color)));
1037 Log.i(TAG,
"set rendering parameters...");
1038 RTABMapLib.
setClusterRatio(nativeApplication, Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_cluster_ratio), getString(R.string.pref_default_cluster_ratio))));
1039 RTABMapLib.
setMaxGainRadius(nativeApplication, Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_gain_max_radius), getString(R.string.pref_default_gain_max_radius))));
1040 RTABMapLib.
setRenderingTextureDecimation(nativeApplication, Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_rendering_texture_decimation), getString(R.string.pref_default_rendering_texture_decimation))));
1042 if(mItemRenderingPointCloud != null)
1044 int renderingType = sharedPref.getInt(getString(R.string.pref_key_rendering), Integer.parseInt(getString(R.string.pref_default_rendering)));
1045 if(renderingType == 0)
1047 mItemRenderingPointCloud.setChecked(
true);
1049 else if(renderingType == 1)
1051 mItemRenderingMesh.setChecked(
true);
1055 mItemRenderingTextureMesh.setChecked(
true);
1059 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
1060 mItemRenderingTextureMesh.isChecked());
1062 mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE);
1067 Log.e(TAG,
"Error parsing preferences: " + e.getMessage());
1068 mToast.makeText(
this, String.format(
"Error parsing preferences: "+e.getMessage()), mToast.LENGTH_LONG).show();
1082 String message =
new String();
1085 if(System.currentTimeMillis()/1000 - mOnPauseStamp < 1)
1087 message = String.format(
"RTAB-Map has been interrupted by another application, Camera should be re-initialized! Set your phone/tablet in Airplane mode if this happens often.");
1091 message = String.format(
"Hold Tight! Initializing Camera Service...");
1093 mToast.makeText(
this,
"Mapping is paused!", mToast.LENGTH_LONG).show();
1097 message = String.format(
"Hold Tight! Initializing Camera Service...\nTip: If the camera is still drifting just after the mapping has started, do \"Reset\".");
1103 if(!DISABLE_LOG) Log.i(TAG, String.format(
"onResume()"));
1110 switch (requestCode) {
1113 if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
1120 Toast.makeText(
this,
"Storage read/write permissions are needed to run this application", Toast.LENGTH_LONG).show();
1129 if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
1131 startCamera(String.format(
"Hold Tight! Initializing Camera Service...\n" 1132 +
"Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
1134 Toast.makeText(
this,
"Camera permission is needed for scanning and motion tracking.", Toast.LENGTH_LONG).show();
1142 if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
1145 Toast.makeText(
this,
"Internet permission is needed to share scans.", Toast.LENGTH_LONG).show();
1164 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1165 String cameraDriverStr = sharedPref.getString(getString(R.string.pref_key_camera_driver), getString(R.string.pref_default_camera_driver));
1166 final boolean depthFromMotion = sharedPref.getBoolean(getString(R.string.pref_key_depth_from_motion),
Boolean.parseBoolean(getString(R.string.pref_default_depth_from_motion)));
1167 mCameraDriver = Integer.parseInt(cameraDriverStr);
1169 if(!DISABLE_LOG) Log.i(TAG, String.format(
"startCamera() driver=%d", mCameraDriver));
1170 if(mCameraDriver == 0)
1174 mToast.makeText(
this,
"Current camera driver selected is Tango, but Tango is not available or outdated on this phone. Abort scanning...", mToast.LENGTH_LONG).show();
1178 if (!Tango.hasPermission(
this, Tango.PERMISSIONTYPE_MOTION_TRACKING)) {
1179 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Asking for motion tracking permission"));
1180 startActivityForResult(
1181 Tango.getRequestPermissionIntent(Tango.PERMISSIONTYPE_MOTION_TRACKING),
1182 Tango.TANGO_INTENT_ACTIVITYCODE);
1188 if(mCameraServiceConnectionUsed)
1190 mProgressDialog.setTitle(
"");
1191 mProgressDialog.setMessage(message);
1192 mProgressDialog.show();
1199 mToast.makeText(
this,
"Current camera driver selected is Tango, but Tango service binding failed. Abort scanning...", mToast.LENGTH_LONG).show();
1203 else if(mCameraDriver == 1 || mCameraDriver == 2 || mCameraDriver == 3)
1205 if((mCameraDriver == 1 || mCameraDriver == 3) && !mIsARCoreAvailable)
1207 mToast.makeText(
this,
"ARCore not supported on this phone! Cannot start a new scan.", mToast.LENGTH_LONG).show();
1210 if(mCameraDriver == 2 && !mIsAREngineAvailable)
1212 mToast.makeText(
this,
"AREngine not supported on this phone! Cannot start a new scan.", mToast.LENGTH_LONG).show();
1217 if(mCameraDriver==1 && !mItemRenderingPointCloud.isChecked())
1219 mItemRenderingPointCloud.setChecked(
true);
1221 Thread bindThread =
new Thread(
new Runnable() {
1224 if(mCameraDriver==1 && !depthFromMotion)
1228 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
1229 mItemRenderingTextureMesh.isChecked());
1232 runOnUiThread(
new Runnable() {
1234 boolean localSuccess = cameraStartSucess;
1235 if(cameraStartSucess && mCameraDriver == 3)
1237 synchronized (
this) {
1239 mProgressDialog.setTitle(
"");
1240 mProgressDialog.setMessage(message);
1241 mProgressDialog.show();
1244 mToast.makeText(
getActivity(),
"Current camera driver selected is ARCore Java, but initialization failed. Abort scanning...", mToast.LENGTH_LONG).show();
1245 mArCoreCamera = null;
1246 localSuccess =
false;
1253 mItemRenderingPointCloud.setChecked(
true);
1255 mToast.makeText(getApplicationContext(),
"Depth camera not found, only poses and RGB images can be recorded.", mToast.LENGTH_LONG).show();
1261 mProgressDialog.dismiss();
1264 mToast.makeText(getApplicationContext(),
1265 String.format(
"Failed to intialize Camera!"), mToast.LENGTH_LONG).show();
1271 mToast.makeText(getApplicationContext(),
"Currently ARCore NDK driver doesn't support depth, only poses, RGB images and 3d features can be recorded.", mToast.LENGTH_LONG).show();
1287 mToast.makeText(
this,
"Supported camera driver not found! Cannot start a new scan.", mToast.LENGTH_LONG).show();
1293 if(!DISABLE_LOG) Log.i(TAG, String.format(
"called setCamera(type=%d);", type));
1297 mStatusTexts[1] = getString(R.string.memory)+String.valueOf(mFreeMemoryOnStart>freeMemory?mFreeMemoryOnStart-freeMemory:0);
1298 mStatusTexts[2] = getString(R.string.free_memory)+String.valueOf(freeMemory);
1303 mSeekBarOrthoCut.setVisibility(type!=3?View.INVISIBLE:View.VISIBLE);
1304 mSeekBarGrid.setVisibility(mSeekBarGrid.isEnabled() && type==3?View.VISIBLE:View.INVISIBLE);
1307 mSeekBarOrthoCut.setMax(120);
1308 mSeekBarOrthoCut.setProgress(80);
1315 switch (v.getId()) {
1316 case R.id.gl_surface_view:
1318 case R.id.start_button:
1321 case R.id.stop_button:
1331 case R.id.light_button:
1334 case R.id.backface_button:
1337 case R.id.wireframe_button:
1340 case R.id.close_visualization_button:
1344 case R.id.button_saveOnDevice:
1347 case R.id.button_shareToSketchfab:
1350 case R.id.button_library:
1353 case R.id.button_new_scan:
1364 if(mSavedRenderingType==0)
1366 mItemRenderingPointCloud.setChecked(
true);
1368 else if(mSavedRenderingType==1)
1370 mItemRenderingMesh.setChecked(
true);
1374 mItemRenderingTextureMesh.setChecked(
true);
1389 Display display = getWindowManager().getDefaultDisplay();
1390 Camera.CameraInfo colorCameraInfo =
new Camera.CameraInfo();
1391 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1392 boolean fisheye = sharedPref.getBoolean(getString(R.string.pref_key_fisheye),
Boolean.parseBoolean(getString(R.string.pref_default_fisheye)));
1393 Camera.getCameraInfo(fisheye?1:0, colorCameraInfo);
1397 class DoubleTapGestureDetector
extends GestureDetector.SimpleOnGestureListener {
1400 public boolean onDoubleTap(MotionEvent event) {
1401 if(!DISABLE_LOG) Log.i(TAG,
"onDoubleTap");
1402 float normalizedX =
event.getX(0) / mScreenSize.x;
1403 float normalizedY =
event.getY(0) / mScreenSize.y;
1404 RTABMapLib.
onTouchEvent(nativeApplication, 3, event.getActionMasked(), normalizedX, normalizedY, 0.0f, 0.0f);
1408 public boolean onSingleTapConfirmed(MotionEvent event) {
1409 if(!DISABLE_LOG) Log.i(TAG,
"onSingleTapConfirmed");
1425 if(!DISABLE_LOG) Log.i(TAG,
"called onCreateOptionsMenu;");
1427 MenuInflater inflater = getMenuInflater();
1428 inflater.inflate(R.menu.optionmenu, menu);
1430 getActionBar().setDisplayShowHomeEnabled(
true);
1431 getActionBar().setIcon(R.drawable.ic_launcher);
1433 mItemSave = menu.findItem(R.id.save);
1434 mItemOpen = menu.findItem(R.id.open);
1435 mItemNewScan = menu.findItem(R.id.new_scan);
1436 mItemPostProcessing = menu.findItem(R.id.post_processing);
1437 mItemExport = menu.findItem(R.id.export);
1438 mItemSettings = menu.findItem(R.id.settings);
1439 mItemModes = menu.findItem(R.id.modes);
1440 mItemResume = menu.findItem(R.id.resume);
1441 mItemLocalizationMode = menu.findItem(R.id.localization_mode);
1442 mItemTrajectoryMode = menu.findItem(R.id.trajectory_mode);
1443 mItemRenderingPointCloud = menu.findItem(R.id.point_cloud);
1444 mItemRenderingMesh = menu.findItem(R.id.mesh);
1445 mItemRenderingTextureMesh = menu.findItem(R.id.texture_mesh);
1446 mItemDataRecorderMode = menu.findItem(R.id.data_recorder);
1447 mItemStatusVisibility = menu.findItem(R.id.status);
1448 mItemDebugVisibility = menu.findItem(R.id.debug);
1449 mItemSave.setEnabled(
false);
1450 mItemNewScan.setEnabled(
true);
1451 mItemExport.setEnabled(
false);
1452 mItemOpen.setEnabled(
true);
1453 mItemPostProcessing.setEnabled(
false);
1454 mItemDataRecorderMode.setEnabled(
false);
1458 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1459 int renderingType = sharedPref.getInt(getString(R.string.pref_key_rendering), Integer.parseInt(getString(R.string.pref_default_rendering)));
1460 if(renderingType == 0)
1462 mItemRenderingPointCloud.setChecked(
true);
1464 else if(renderingType == 1)
1466 mItemRenderingMesh.setChecked(
true);
1470 mItemRenderingTextureMesh.setChecked(
true);
1474 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
1475 mItemRenderingTextureMesh.isChecked());
1477 if(mButtonBackfaceShown != null)
1479 mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE);
1484 Log.e(TAG,
"Error parsing rendering preferences: " + e.getMessage());
1485 mToast.makeText(
this, String.format(
"Error parsing rendering preferences: "+e.getMessage()), mToast.LENGTH_LONG).show();
1495 MemoryInfo mi =
new MemoryInfo();
1496 ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
1497 activityManager.getMemoryInfo(mi);
1498 return mi.availMem / 0x100000L;
1503 if(mItemStatusVisibility != null && mItemDebugVisibility != null)
1515 mRenderer.
updateTexts(Arrays.copyOfRange(mStatusTexts, 0, STATUS_TEXTS_POSE_INDEX-1));
1517 else if(mItemDebugVisibility.isChecked())
1519 mRenderer.
updateTexts(Arrays.copyOfRange(mStatusTexts, STATUS_TEXTS_POSE_INDEX-1, mStatusTexts.length));
1526 if(mGLView.getRenderMode() == GLSurfaceView.RENDERMODE_WHEN_DIRTY)
1528 mGLView.requestRender();
1537 float optimizationMaxError,
1538 float optimizationMaxErrorRatio,
1539 boolean fastMovement,
1540 int landmarkDetected,
1541 String[] statusTexts)
1543 for(
int i = 1; i<mStatusTexts.length && i<statusTexts.length; ++i)
1545 mStatusTexts[i] = statusTexts[i];
1549 String updateValue = mUpdateRate.compareTo(
"0")==0?
"Max":
mUpdateRate;
1550 mStatusTexts[0] = getString(R.string.status)+(mItemDataRecorderMode!=null&&mItemDataRecorderMode.isChecked()?String.format(
"Recording (%s Hz)", updateValue):mItemLocalizationMode!=null && mItemLocalizationMode.isChecked()?String.format(
"Localization (%s Hz)", updateValue):String.format(
"Mapping (%s Hz)", updateValue));
1557 if(mButtonStart.getVisibility() != View.VISIBLE)
1561 long memoryUsed = mFreeMemoryOnStart>memoryFree?mFreeMemoryOnStart-memoryFree:0;
1563 if(memoryFree < 400)
1567 if(mMemoryWarningDialog!=null)
1569 mMemoryWarningDialog.dismiss();
1570 mMemoryWarningDialog = null;
1573 mMemoryWarningDialog =
new AlertDialog.Builder(
getActivity())
1574 .setTitle(
"Memory is full!")
1575 .setCancelable(
false)
1576 .setMessage(String.format(
"Scanning has been paused because free memory is too " 1577 +
"low (%d MB). You should be able to save the database but some post-processing and exporting options may fail. " 1578 +
"\n\nNote that for large environments, you can save multiple databases and " 1579 +
"merge them with RTAB-Map Desktop version.", memoryUsed))
1580 .setPositiveButton(
"Ok",
new DialogInterface.OnClickListener() {
1581 public void onClick(DialogInterface dialog,
int which) {
1582 mMemoryWarningDialog = null;
1585 .setNeutralButton(
"Save",
new DialogInterface.OnClickListener() {
1586 public void onClick(DialogInterface dialog,
int which) {
1588 mMemoryWarningDialog = null;
1592 mMemoryWarningDialog.setCanceledOnTouchOutside(
false);
1593 mMemoryWarningDialog.show();
1595 else if(mMemoryWarningDialog == null && memoryUsed*3 > memoryFree && (mItemDataRecorderMode == null || !mItemDataRecorderMode.isChecked()))
1597 mMemoryWarningDialog =
new AlertDialog.Builder(
getActivity())
1598 .setTitle(
"Warning: Memory is almost full!")
1599 .setCancelable(
false)
1600 .setMessage(String.format(
"Free memory (%d MB) should be at least 3 times the " 1601 +
"memory used (%d MB) so that some post-processing and exporting options " 1602 +
"have enough memory to work correctly. If you just want to save the database " 1603 +
"after scanning, you can continue until the next warning.\n\n" 1604 +
"Note that showing only point clouds reduces memory needed for rendering.", memoryFree, memoryUsed))
1605 .setPositiveButton(
"Pause",
new DialogInterface.OnClickListener() {
1606 public void onClick(DialogInterface dialog,
int which) {
1610 .setNeutralButton(
"Continue",
new DialogInterface.OnClickListener() {
1611 public void onClick(DialogInterface dialog,
int which) {
1615 mMemoryWarningDialog.setCanceledOnTouchOutside(
false);
1616 mMemoryWarningDialog.show();
1624 long currentTime = System.currentTimeMillis()/1000;
1625 if(loopClosureId > 0)
1627 mToast.setText(String.format(
"Loop closure detected! (%d/%d inliers)", inliers, matches));
1630 else if(landmarkDetected != 0)
1632 mToast.setText(String.format(
"Marker %d detected!", landmarkDetected));
1635 else if(rejected > 0)
1637 if(inliers >= Integer.parseInt(mMinInliers))
1639 if(optimizationMaxError > 0.0
f)
1641 mToast.setText(String.format(
"Loop closure rejected, too high graph optimization error (%.3fm: ratio=%.3f < factor=%sx).", optimizationMaxError, optimizationMaxErrorRatio, mMaxOptimizationError));
1645 mToast.setText(String.format(
"Loop closure rejected, graph optimization failed! You may try a different Graph Optimizer (see Mapping options)."));
1650 mToast.setText(String.format(
"Loop closure rejected, not enough inliers (%d/%d < %s).", inliers, matches, mMinInliers));
1654 else if(fastMovement)
1656 if(currentTime - mLastFastMovementNotificationStamp > 3)
1658 mToast.setText(
"Move slower... blurry images are not added to map (\"Settings->Mapping...->Maximum Motion Speed\" is enabled).");
1665 mLastFastMovementNotificationStamp = currentTime;
1676 final float updateTime,
1677 final int loopClosureId,
1678 final int highestHypId,
1679 final int databaseMemoryUsed,
1682 final int featuresExtracted,
1683 final float hypothesis,
1684 final int nodesDrawn,
1687 final float rehearsalValue,
1688 final float optimizationMaxError,
1689 final float optimizationMaxErrorRatio,
1690 final float distanceTravelled,
1691 final int fastMovement,
1692 final int landmarkDetected,
1700 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateStatsCallback()"));
1705 statusTexts[1] = getString(R.string.memory)+(mFreeMemoryOnStart>memoryFree?mFreeMemoryOnStart-memoryFree:0);
1706 statusTexts[2] = getString(R.string.free_memory)+memoryFree;
1708 if(loopClosureId > 0)
1717 if(mLastKnownLocation != null)
1719 long millisec = System.currentTimeMillis() - mLastKnownLocation.getTime();
1722 statusTexts[3] = getString(R.string.gps)+String.format(
"[too old, %d ms]", millisec);
1726 statusTexts[3] = getString(R.string.gps)+
1727 String.format(
"%.2f %.2f %.2fm %.0fdeg %.0fm",
1728 mLastKnownLocation.getLongitude(),
1729 mLastKnownLocation.getLatitude(),
1730 mLastKnownLocation.getAltitude(),
1732 mLastKnownLocation.getAccuracy());
1737 statusTexts[3] = getString(R.string.gps)+String.format(
"[not yet available, %.0fdeg]", mCompassDeg);
1740 if(mEnvSensorsSaved)
1742 statusTexts[4] = getString(R.string.env_sensors);
1744 if(mLastEnvSensorsSet[0])
1746 statusTexts[4] += String.format(
" %.0f dbm", mLastEnvSensors[0]);
1747 mLastEnvSensorsSet[0] =
false;
1749 if(mLastEnvSensorsSet[1])
1751 statusTexts[4] += String.format(
" %.1f %cC", mLastEnvSensors[1],
'\u00B0');
1752 mLastEnvSensorsSet[1] =
false;
1754 if(mLastEnvSensorsSet[2])
1756 statusTexts[4] += String.format(
" %.1f hPa", mLastEnvSensors[2]);
1757 mLastEnvSensorsSet[2] =
false;
1759 if(mLastEnvSensorsSet[3])
1761 statusTexts[4] += String.format(
" %.0f lx", mLastEnvSensors[3]);
1762 mLastEnvSensorsSet[3] =
false;
1764 if(mLastEnvSensorsSet[4])
1766 statusTexts[4] += String.format(
" %.0f %%", mLastEnvSensors[4]);
1767 mLastEnvSensorsSet[4] =
false;
1771 String formattedDate =
new SimpleDateFormat(
"HH:mm:ss.SSS").format(
new Date());
1772 statusTexts[5] = getString(R.string.time)+formattedDate;
1775 statusTexts[index++] = getString(R.string.nodes)+nodes+
" (" + nodesDrawn +
" shown)";
1776 statusTexts[index++] = getString(R.string.words)+words;
1777 statusTexts[index++] = getString(R.string.database_size)+databaseMemoryUsed;
1778 statusTexts[index++] = getString(R.string.points)+points;
1779 statusTexts[index++] = getString(R.string.polygons)+polygons;
1780 statusTexts[index++] = getString(R.string.update_time)+(int)(updateTime) +
" / " + (mTimeThr.compareTo(
"0")==0?
"No Limit":
mTimeThr);
1781 statusTexts[index++] = getString(R.string.features)+featuresExtracted +
" / " + (mMaxFeatures.compareTo(
"0")==0?
"No Limit":mMaxFeatures.compareTo(
"-1")==0?
"Disabled":
mMaxFeatures);
1782 statusTexts[index++] = getString(R.string.rehearsal)+(int)(rehearsalValue*100.0
f);
1784 statusTexts[index++] = getString(R.string.inliers)+inliers;
1785 statusTexts[index++] = getString(R.string.hypothesis)+(int)(hypothesis*100.0f) +
" / " + (int)(Float.parseFloat(mLoopThr)*100.0f) +
" (" + (loopClosureId>0?loopClosureId:highestHypId)+
")";
1786 statusTexts[index++] = getString(R.string.fps)+(int)fps+
" Hz";
1787 statusTexts[index++] = getString(R.string.distance)+(int)distanceTravelled+
" m";
1788 statusTexts[index++] = String.format(
"Pose (x,y,z): %.2f %.2f %.2f", x,y,z);
1790 runOnUiThread(
new Runnable() {
1792 updateStatsUI(loopClosureId, inliers, matches, rejected, optimizationMaxError, optimizationMaxErrorRatio, fastMovement!=0, landmarkDetected, statusTexts);
1801 if(!DISABLE_LOG) Log.i(TAG, String.format(
"rtabmapInitEventsUI() status=%d msg=%s", status, msg));
1803 int optimizedMeshDetected = 0;
1805 if(msg.equals(
"Loading optimized cloud...done!"))
1807 optimizedMeshDetected = 1;
1809 else if(msg.equals(
"Loading optimized mesh...done!"))
1811 optimizedMeshDetected = 2;
1813 else if(msg.equals(
"Loading optimized texture mesh...done!"))
1815 optimizedMeshDetected = 3;
1817 if(optimizedMeshDetected > 0)
1820 mSavedRenderingType = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2;
1821 if(optimizedMeshDetected==1)
1823 mItemRenderingPointCloud.setChecked(
true);
1825 else if(optimizedMeshDetected==2)
1827 mItemRenderingMesh.setChecked(
true);
1831 mItemRenderingTextureMesh.setChecked(
true);
1835 if(mButtonCameraView.getSelectedItemPosition() == 0)
1839 mToast.makeText(
getActivity(), String.format(
"Optimized mesh detected in the database, it is shown while the database is loading..."), mToast.LENGTH_LONG).show();
1840 mProgressDialog.dismiss();
1843 if(mButtonStart!=null)
1845 mStatusTexts[0] = getString(R.string.status)+(status == 1 && msg.isEmpty()?mState ==
State.
STATE_CAMERA?
"Camera Preview":
"Idle":msg);
1848 mStatusTexts[1] = getString(R.string.memory)+String.valueOf(mFreeMemoryOnStart>freeMemory?mFreeMemoryOnStart-freeMemory:0);
1849 mStatusTexts[2] = getString(R.string.free_memory)+String.valueOf(freeMemory);
1859 if(!DISABLE_LOG) Log.i(TAG, String.format(
"rtabmapInitEventCallback()"));
1861 runOnUiThread(
new Runnable() {
1872 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateProgressionUI() count=%d max=%s", count, max));
1874 mExportProgressDialog.setMax(max);
1875 mExportProgressDialog.setProgress(count);
1883 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateProgressionCallback()"));
1885 runOnUiThread(
new Runnable() {
1909 if(key.equals(
"TangoServiceException"))
1910 str = String.format(
"Tango service exception: %s", value);
1911 else if(key.equals(
"FisheyeOverExposed"))
1913 else if(key.equals(
"FisheyeUnderExposed"))
1915 else if(key.equals(
"ColorOverExposed"))
1917 else if(key.equals(
"ColorUnderExposed"))
1919 else if(key.equals(
"CameraTango"))
1921 else if(key.equals(
"TooFewFeaturesTracked"))
1923 if(!value.equals(
"0"))
1925 str = String.format(
"Too few features (%s) were tracked in the fisheye image. This may result in poor odometry!", value);
1928 else if(key.equals(
"TooClose"))
1932 str = String.format(
"Too close! Tip: Scan from at least ~1 meter from surfaces.", value);
1935 else if(key.equals(
"TangoPoseEventNotReceived"))
1937 str = String.format(
"No valid tango pose event received since %s sec.", value);
1941 str = String.format(
"Unknown Camera event detected!? (type=%d, key=%s, value=%s)", type, key, value);
1945 mToast.setText(str);
1956 runOnUiThread(
new Runnable() {
1964 int versionNumber = 0;
1967 PackageInfo
pi = getApplicationContext().getPackageManager().getPackageInfo(packageName,
1968 PackageManager.GET_META_DATA);
1969 versionNumber = pi.versionCode;
1970 }
catch (NameNotFoundException
e) {
1971 e.printStackTrace();
1973 return (minVersion <= versionNumber);
1980 mExportProgressDialog.setTitle(
"Post-Processing");
1981 mExportProgressDialog.setMessage(String.format(
"Please wait while optimizing..."));
1982 mExportProgressDialog.setProgress(0);
1983 mExportProgressDialog.show();
1986 Thread workingThread =
new Thread(
new Runnable() {
1989 runOnUiThread(
new Runnable() {
1991 if(mExportProgressDialog.isShowing())
1993 mExportProgressDialog.dismiss();
1994 if(loopDetected >= 0)
1996 mTotalLoopClosures+=loopDetected;
1997 if(withStandardMeshExport)
1999 export(
true,
true,
false,
true, 200000);
2003 mProgressDialog.setTitle(
"Post-Processing");
2004 mProgressDialog.setMessage(String.format(
"Optimization done! Increasing visual appeal..."));
2005 mProgressDialog.show();
2007 if(mOpenedDatabasePath.isEmpty())
2013 else if(loopDetected < 0)
2015 mToast.makeText(
getActivity(), String.format(
"Optimization failed!"), mToast.LENGTH_LONG).show();
2020 mProgressDialog.dismiss();
2021 mToast.makeText(
getActivity(), String.format(
"Optimization canceled"), mToast.LENGTH_LONG).show();
2029 workingThread.start();
2033 public void handleMessage(Message msg) {
2043 mHudVisible =
false;
2062 if(mItemSave != null)
2068 notouchHandler.removeCallbacks(notouchCallback);
2069 notouchHandler.postDelayed(notouchCallback, NOTOUCH_TIMEOUT);
2071 if(mGLView.getRenderMode() == GLSurfaceView.RENDERMODE_WHEN_DIRTY)
2073 mGLView.requestRender();
2078 notouchHandler.removeCallbacks(notouchCallback);
2079 Timer timer =
new Timer();
2087 mToast.makeText(
getActivity(), String.format(
"Re-adding %d online clouds, this may take some time...", mMapNodes), mToast.LENGTH_LONG).show();
2090 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateState() state=%s hud=%d", state.toString(), mHudVisible?1:0));
2091 mStatusTexts[0] = state.toString();
2096 mButtonLighting.setVisibility(View.INVISIBLE);
2097 mButtonWireframe.setVisibility(View.INVISIBLE);
2098 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
2099 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2100 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2101 mButtonLibrary.setVisibility(View.INVISIBLE);
2102 mButtonNewScan.setVisibility(View.INVISIBLE);
2103 mItemSave.setEnabled(
false);
2104 mItemExport.setEnabled(
false);
2105 mItemOpen.setEnabled(
false);
2106 mItemNewScan.setEnabled(
true);
2107 mItemPostProcessing.setEnabled(
false);
2108 mItemSettings.setEnabled(
false);
2109 mItemResume.setEnabled(
false);
2111 mItemLocalizationMode.setEnabled(
true);
2112 mItemTrajectoryMode.setEnabled(
true);
2113 mItemDataRecorderMode.setEnabled(
true);
2114 mButtonStart.setVisibility(mState ==
State.
STATE_CAMERA?View.VISIBLE:View.INVISIBLE);
2115 mButtonStop.setVisibility(mHudVisible && mState ==
State.
STATE_MAPPING?View.VISIBLE:View.INVISIBLE);
2117 case STATE_PROCESSING:
2118 mButtonLighting.setVisibility(View.INVISIBLE);
2119 mButtonWireframe.setVisibility(View.INVISIBLE);
2120 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
2121 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2122 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2123 mButtonLibrary.setVisibility(View.INVISIBLE);
2124 mButtonNewScan.setVisibility(View.INVISIBLE);
2125 mItemSave.setEnabled(
false);
2126 mItemExport.setEnabled(
false);
2127 mItemOpen.setEnabled(
false);
2128 mItemNewScan.setEnabled(
false);
2129 mItemPostProcessing.setEnabled(
false);
2130 mItemSettings.setEnabled(
false);
2131 mItemResume.setEnabled(
false);
2132 mItemModes.setEnabled(
false);
2133 mButtonStart.setVisibility(View.INVISIBLE);
2134 mButtonStop.setVisibility(View.INVISIBLE);
2136 case STATE_VISUALIZING:
2137 case STATE_VISUALIZING_CAMERA:
2138 mButtonLighting.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2139 mButtonWireframe.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2141 mButtonCloseVisualization.setEnabled(
true);
2144 mButtonLibrary.setVisibility(View.INVISIBLE);
2145 mButtonNewScan.setVisibility(View.INVISIBLE);
2150 mItemPostProcessing.setEnabled(
false);
2154 mItemLocalizationMode.setEnabled(
true);
2155 mItemTrajectoryMode.setEnabled(
false);
2156 mItemDataRecorderMode.setEnabled(
false);
2157 mButtonStart.setVisibility(View.INVISIBLE);
2160 case STATE_VISUALIZING_WHILE_LOADING:
2161 mButtonLighting.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2162 mButtonWireframe.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2163 mButtonCloseVisualization.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE);
2164 mButtonCloseVisualization.setEnabled(
false);
2165 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2166 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2167 mButtonLibrary.setVisibility(View.INVISIBLE);
2168 mButtonNewScan.setVisibility(View.INVISIBLE);
2169 mItemSave.setEnabled(
false);
2170 mItemExport.setEnabled(
false);
2171 mItemOpen.setEnabled(
false);
2172 mItemPostProcessing.setEnabled(
false);
2173 mItemSettings.setEnabled(
false);
2174 mItemResume.setEnabled(
false);
2175 mItemModes.setEnabled(
false);
2176 mButtonStart.setVisibility(View.INVISIBLE);
2177 mButtonStop.setVisibility(View.INVISIBLE);
2180 mButtonLighting.setVisibility(View.INVISIBLE);
2181 mButtonWireframe.setVisibility(View.INVISIBLE);
2182 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
2183 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2184 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2185 mButtonLibrary.setVisibility(mState==
State.
STATE_WELCOME?View.VISIBLE:View.INVISIBLE);
2186 mButtonNewScan.setVisibility(mState==
State.
STATE_WELCOME?View.VISIBLE:View.INVISIBLE);
2187 mItemSave.setEnabled(mMapNodes>0);
2188 mItemExport.setEnabled(mMapNodes>0);
2189 mItemOpen.setEnabled(
true);
2190 mItemNewScan.setEnabled(
true);
2191 mItemPostProcessing.setEnabled(mMapNodes>0);
2192 mItemSettings.setEnabled(
true);
2193 mItemResume.setEnabled(mMapNodes>0);
2194 mItemModes.setEnabled(
true);
2195 mButtonStart.setVisibility(View.INVISIBLE);
2196 mButtonStop.setVisibility(View.INVISIBLE);
2197 mItemLocalizationMode.setEnabled(
true);
2198 mItemDataRecorderMode.setEnabled(
true);
2199 mItemTrajectoryMode.setEnabled(
true);
2202 mButtonCameraView.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE);
2203 mButtonBackfaceShown.setVisibility(mHudVisible && (mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked())?View.VISIBLE:View.INVISIBLE);
2204 mSeekBarOrthoCut.setVisibility(mHudVisible && mButtonCameraView.getSelectedItemPosition() == 3?View.VISIBLE:View.INVISIBLE);
2205 mSeekBarGrid.setVisibility(mHudVisible && mSeekBarGrid.isEnabled() && mButtonCameraView.getSelectedItemPosition() == 3?View.VISIBLE:View.INVISIBLE);
2209 mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
2210 mGLView.requestRender();
2214 mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
2219 if(!DISABLE_LOG) Log.i(TAG, String.format(
"startMapping()"));
2223 if(mMemoryWarningDialog != null)
2225 mMemoryWarningDialog.dismiss();
2226 mMemoryWarningDialog=null;
2229 mLastFastMovementNotificationStamp = System.currentTimeMillis()/1000;
2231 if(mItemDataRecorderMode.isChecked())
2233 mToast.makeText(
getActivity(), String.format(
"Data Recorder Mode: no map is created, only raw data is recorded."), mToast.LENGTH_LONG).show();
2235 else if(mMapNodes>0)
2237 if(mItemLocalizationMode!=null && mItemLocalizationMode.isChecked())
2239 mToast.makeText(
getActivity(), String.format(
"Localization mode"), mToast.LENGTH_LONG).show();
2243 mToast.makeText(
getActivity(), String.format(
"On resume, a new map is created. Tip: Try relocalizing in the previous area."), mToast.LENGTH_LONG).show();
2246 else if(mMapNodes==0 && mItemLocalizationMode!=null && mItemLocalizationMode.isChecked())
2248 mItemLocalizationMode.setChecked(
false);
2250 mToast.makeText(
getActivity(), String.format(
"Disabled localization mode as the map is empty, now mapping..."), mToast.LENGTH_LONG).show();
2256 mProgressDialog.setTitle(
"");
2257 mProgressDialog.setMessage(
"Stopping camera...");
2258 mProgressDialog.show();
2277 if(mArCoreCamera != null)
2279 synchronized (
this) {
2281 mArCoreCamera.
close();
2282 mArCoreCamera = null;
2286 Thread stopThread =
new Thread(
new Runnable() {
2288 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopCamera()"));
2290 if(mCameraServiceConnectionUsed)
2292 if(!DISABLE_LOG) Log.i(TAG, String.format(
"unbindService"));
2293 getActivity().unbindService(mCameraServiceConnection);
2295 mCameraServiceConnectionUsed =
false;
2297 runOnUiThread(
new Runnable() {
2300 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopMapping(): runOnUiThread"));
2301 mProgressDialog.dismiss();
2311 mProgressDialog.setTitle(
"");
2312 mProgressDialog.setMessage(
"Stopping camera...");
2313 mProgressDialog.show();
2317 if(mArCoreCamera != null)
2319 synchronized (
this) {
2321 mArCoreCamera.
close();
2322 mArCoreCamera = null;
2326 Thread stopThread =
new Thread(
new Runnable() {
2328 if(!DISABLE_LOG) Log.i(TAG, String.format(
"setPausedMapping()"));
2330 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopCamera()"));
2332 if(mCameraServiceConnectionUsed)
2334 if(!DISABLE_LOG) Log.i(TAG, String.format(
"unbindService"));
2335 getActivity().unbindService(mCameraServiceConnection);
2337 mCameraServiceConnectionUsed =
false;
2339 runOnUiThread(
new Runnable() {
2341 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopMapping(): runOnUiThread"));
2342 mProgressDialog.dismiss();
2347 mStatusTexts[1] = getString(R.string.memory)+String.valueOf(mFreeMemoryOnStart>freeMemory?mFreeMemoryOnStart-freeMemory:0);
2348 mStatusTexts[2] = getString(R.string.free_memory)+String.valueOf(freeMemory);
2351 mDateOnPause =
new Date();
2354 if(!mOnPause && !mItemLocalizationMode.isChecked() && !mItemDataRecorderMode.isChecked() && memoryFree >= 100 && mMapNodes>2)
2356 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Do standard processing>?"));
2358 AlertDialog d2 =
new AlertDialog.Builder(
getActivity())
2359 .setCancelable(
false)
2360 .setTitle(
"Mapping Stopped! Optimize Now?")
2361 .setMessage(
"Do you want to do standard graph and mesh optimizations now? This can be also done later using \"Optimize\" and \"Export\" menus.")
2362 .setNeutralButton(
"Only Graph",
new DialogInterface.OnClickListener() {
2363 public void onClick(DialogInterface dialog,
int which) {
2367 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
2368 public void onClick(DialogInterface dialog,
int which) {
2372 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
2373 public void onClick(DialogInterface dialog,
int which) {
2374 if(mOpenedDatabasePath.isEmpty())
2381 d2.setCanceledOnTouchOutside(
false);
2393 if(!DISABLE_LOG) Log.i(TAG,
"called onOptionsItemSelected; selected item: " + item);
2394 int itemId = item.getItemId();
2395 if (itemId == R.id.post_processing_standard)
2399 else if (itemId == R.id.detect_more_loop_closures)
2401 mProgressDialog.setTitle(
"Post-Processing");
2402 mProgressDialog.setMessage(String.format(
"Please wait while detecting more loop closures..."));
2403 mProgressDialog.show();
2405 Thread workingThread =
new Thread(
new Runnable() {
2408 runOnUiThread(
new Runnable() {
2410 mProgressDialog.dismiss();
2411 if(loopDetected >= 0)
2413 mTotalLoopClosures+=loopDetected;
2414 mToast.makeText(
getActivity(), String.format(
"Detection done! %d new loop closure(s) added.", loopDetected), mToast.LENGTH_SHORT).show();
2416 else if(loopDetected < 0)
2418 mToast.makeText(
getActivity(), String.format(
"Detection failed!"), mToast.LENGTH_SHORT).show();
2425 workingThread.start();
2427 else if (itemId == R.id.global_graph_optimization)
2429 mProgressDialog.setTitle(
"Post-Processing");
2430 mProgressDialog.setMessage(String.format(
"Global graph optimization..."));
2431 mProgressDialog.show();
2433 Thread workingThread =
new Thread(
new Runnable() {
2436 runOnUiThread(
new Runnable() {
2438 mProgressDialog.dismiss();
2441 mToast.makeText(
getActivity(), String.format(
"Optimization done!"), mToast.LENGTH_SHORT).show();
2445 mToast.makeText(
getActivity(), String.format(
"Optimization failed!"), mToast.LENGTH_SHORT).show();
2452 workingThread.start();
2454 else if (itemId == R.id.polygons_filtering)
2456 mProgressDialog.setTitle(
"Post-Processing");
2457 mProgressDialog.setMessage(String.format(
"Noise filtering..."));
2458 mProgressDialog.show();
2461 else if (itemId == R.id.gain_compensation_fast)
2463 mProgressDialog.setTitle(
"Post-Processing");
2464 mProgressDialog.setMessage(String.format(
"Adjusting Colors (Fast)..."));
2465 mProgressDialog.show();
2468 else if (itemId == R.id.gain_compensation_full)
2470 mProgressDialog.setTitle(
"Post-Processing");
2471 mProgressDialog.setMessage(String.format(
"Adjusting Colors (Full)..."));
2472 mProgressDialog.show();
2475 else if (itemId == R.id.bilateral_filtering)
2477 mProgressDialog.setTitle(
"Post-Processing");
2478 mProgressDialog.setMessage(String.format(
"Mesh smoothing..."));
2479 mProgressDialog.show();
2482 else if (itemId == R.id.sba)
2484 mProgressDialog.setTitle(
"Post-Processing");
2485 mProgressDialog.setMessage(String.format(
"Bundle adjustement..."));
2486 mProgressDialog.show();
2488 Thread workingThread =
new Thread(
new Runnable() {
2491 runOnUiThread(
new Runnable() {
2493 mProgressDialog.dismiss();
2496 mToast.makeText(
getActivity(), String.format(
"Optimization done!"), mToast.LENGTH_SHORT).show();
2500 mToast.makeText(
getActivity(), String.format(
"Optimization failed!"), mToast.LENGTH_SHORT).show();
2506 workingThread.start();
2508 else if(itemId == R.id.status)
2510 item.setChecked(!item.isChecked());
2513 else if(itemId == R.id.debug)
2515 item.setChecked(!item.isChecked());
2518 else if(itemId == R.id.mesh || itemId == R.id.texture_mesh || itemId == R.id.point_cloud)
2520 item.setChecked(
true);
2523 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
2524 mItemRenderingTextureMesh.isChecked());
2531 int type = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2;
2532 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
2533 SharedPreferences.Editor editor = sharedPref.edit();
2534 editor.putInt(getString(R.string.pref_key_rendering), type);
2539 else if(itemId == R.id.map_shown)
2541 item.setChecked(!item.isChecked());
2544 else if(itemId == R.id.odom_shown)
2546 item.setChecked(!item.isChecked());
2549 else if(itemId == R.id.localization_mode)
2551 item.setChecked(!item.isChecked());
2554 else if(itemId == R.id.trajectory_mode)
2556 item.setChecked(!item.isChecked());
2560 else if(itemId == R.id.graph_optimization)
2562 item.setChecked(!item.isChecked());
2565 else if(itemId == R.id.graph_visible)
2567 item.setChecked(!item.isChecked());
2570 else if(itemId == R.id.grid_visible)
2572 item.setChecked(!item.isChecked());
2573 mSeekBarGrid.setEnabled(item.isChecked());
2574 mSeekBarGrid.setVisibility(mHudVisible && mSeekBarGrid.isEnabled()&&mButtonCameraView.getSelectedItemPosition() == 3?View.VISIBLE:View.INVISIBLE);
2577 else if (itemId == R.id.save)
2581 else if(itemId == R.id.resume)
2585 else if(itemId == R.id.new_scan)
2589 else if(itemId == R.id.data_recorder)
2591 final boolean dataRecorderOldState = item.isChecked();
2592 AlertDialog d2 =
new AlertDialog.Builder(
getActivity())
2593 .setCancelable(
false)
2594 .setTitle(
"Data Recorder Mode")
2595 .setMessage(
"Changing from/to data recorder mode will close the current session. Do you want to continue?")
2596 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
2597 public void onClick(DialogInterface dialog,
int which) {
2599 mTotalLoopClosures = 0;
2602 mStatusTexts[index++] = getString(R.string.nodes)+0;
2603 mStatusTexts[index++] = getString(R.string.words)+0;
2604 mStatusTexts[index++] = getString(R.string.database_size)+0;
2605 mStatusTexts[index++] = getString(R.string.points)+0;
2606 mStatusTexts[index++] = getString(R.string.polygons)+0;
2607 mStatusTexts[index++] = getString(R.string.update_time)+0;
2608 mStatusTexts[index++] = getString(R.string.features)+0;
2609 mStatusTexts[index++] = getString(R.string.rehearsal)+0;
2610 mStatusTexts[index++] = getString(R.string.total_loop)+0;
2611 mStatusTexts[index++] = getString(R.string.inliers)+0;
2612 mStatusTexts[index++] = getString(R.string.hypothesis)+0;
2613 mStatusTexts[index++] = getString(R.string.fps)+0;
2614 mStatusTexts[index++] = getString(R.string.distance)+0;
2615 mStatusTexts[index++] = String.format(
"Pose (x,y,z): 0 0 0");
2618 mItemDataRecorderMode.setChecked(!dataRecorderOldState);
2621 mOpenedDatabasePath =
"";
2622 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
getActivity());
2623 boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory),
Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
2627 mItemLocalizationMode.setEnabled(!mItemDataRecorderMode.isChecked());
2629 if(mItemDataRecorderMode.isChecked())
2631 mToast.makeText(
getActivity(), String.format(
"Data recorder mode activated! Tip: You can increase data update rate in Parameters menu under Mapping options."), mToast.LENGTH_LONG).show();
2635 mToast.makeText(
getActivity(), String.format(
"Data recorder mode deactivated!"), mToast.LENGTH_LONG).show();
2639 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
2640 public void onClick(DialogInterface dialog,
int which) {
2645 d2.setCanceledOnTouchOutside(
false);
2648 else if(itemId == R.id.export_point_cloud ||
2649 itemId == R.id.export_point_cloud_highrez)
2651 final boolean regenerateCloud = itemId == R.id.export_point_cloud_highrez;
2653 export(
false,
false, regenerateCloud,
false, 0);
2655 else if(itemId == R.id.export_optimized_mesh ||
2656 itemId == R.id.export_optimized_mesh_texture)
2658 final boolean isOBJ = itemId == R.id.export_optimized_mesh_texture;
2660 RelativeLayout linearLayout =
new RelativeLayout(
this);
2661 final NumberPicker aNumberPicker =
new NumberPicker(
this);
2662 aNumberPicker.setMaxValue(9);
2663 aNumberPicker.setMinValue(0);
2664 aNumberPicker.setWrapSelectorWheel(
false);
2665 aNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
2666 aNumberPicker.setFormatter(
new NumberPicker.Formatter() {
2668 public String format(
int i) {
2673 return String.format(
"%d00 000", i);
2676 aNumberPicker.setValue(2);
2680 Method method = aNumberPicker.getClass().getDeclaredMethod(
"changeValueByOne",
boolean.
class);
2681 method.setAccessible(
true);
2682 method.invoke(aNumberPicker,
true);
2683 }
catch (NoSuchMethodException
e) {
2684 e.printStackTrace();
2685 }
catch (IllegalArgumentException e) {
2686 e.printStackTrace();
2687 }
catch (IllegalAccessException e) {
2688 e.printStackTrace();
2689 }
catch (InvocationTargetException e) {
2690 e.printStackTrace();
2694 RelativeLayout.LayoutParams params =
new RelativeLayout.LayoutParams(50, 50);
2695 RelativeLayout.LayoutParams numPicerParams =
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
2696 numPicerParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
2698 linearLayout.setLayoutParams(params);
2699 linearLayout.addView(aNumberPicker,numPicerParams);
2701 AlertDialog ad =
new AlertDialog.Builder(
this)
2702 .setTitle(
"Maximum polygons")
2703 .setView(linearLayout)
2704 .setCancelable(
false)
2705 .setPositiveButton(
"Ok",
2706 new DialogInterface.OnClickListener() {
2707 public void onClick(DialogInterface dialog,
2709 export(isOBJ,
true,
false,
true, aNumberPicker.getValue()*100000);
2712 .setNegativeButton(
"Cancel",
2713 new DialogInterface.OnClickListener() {
2714 public void onClick(DialogInterface dialog,
2719 ad.setCanceledOnTouchOutside(
false);
2722 else if(itemId == R.id.open)
2726 else if(itemId == R.id.settings)
2729 startActivity(intent);
2731 else if(itemId == R.id.about)
2734 about.setTitle(
"About RTAB-Map");
2744 startCamera(String.format(
"Hold Tight! Initializing Camera Service...\n" 2745 +
"Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
2756 mTotalLoopClosures = 0;
2760 mStatusTexts[index++] = getString(R.string.nodes)+0;
2761 mStatusTexts[index++] = getString(R.string.words)+0;
2762 mStatusTexts[index++] = getString(R.string.database_size)+0;
2763 mStatusTexts[index++] = getString(R.string.points)+0;
2764 mStatusTexts[index++] = getString(R.string.polygons)+0;
2765 mStatusTexts[index++] = getString(R.string.update_time)+0;
2766 mStatusTexts[index++] = getString(R.string.features)+0;
2767 mStatusTexts[index++] = getString(R.string.rehearsal)+0;
2768 mStatusTexts[index++] = getString(R.string.total_loop)+0;
2769 mStatusTexts[index++] = getString(R.string.inliers)+0;
2770 mStatusTexts[index++] = getString(R.string.hypothesis)+0;
2771 mStatusTexts[index++] = getString(R.string.fps)+0;
2772 mStatusTexts[index++] = getString(R.string.distance)+0;
2773 mStatusTexts[index++] = String.format(
"Pose (x,y,z): 0 0 0");
2776 mOpenedDatabasePath =
"";
2777 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
2778 boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory),
Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
2785 startCamera(String.format(
"Hold Tight! Initializing Camera Service...\n" 2786 +
"Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
2793 if(files.length > 0)
2795 String[] filesWithSize =
new String[files.length];
2796 for(
int i = 0; i<filesWithSize.length; ++i)
2798 File filePath =
new File(mWorkingDirectory+files[i]);
2799 long mb = filePath.length()/(1024*1024);
2800 filesWithSize[i] = files[i] +
" ("+mb+
" MB)";
2803 ArrayList<HashMap<String, String> > arrayList =
new ArrayList<HashMap<String, String> >();
2804 for (
int i = 0; i < filesWithSize.length; i++) {
2805 HashMap<String, String> hashMap =
new HashMap<String, String>();
2806 hashMap.put(
"name", filesWithSize[i]);
2807 hashMap.put(
"path", mWorkingDirectory + files[i]);
2808 arrayList.add(hashMap);
2810 String[] from = {
"name",
"path"};
2811 int[] to = {R.id.textView, R.id.imageView};
2814 AlertDialog.Builder builder =
new AlertDialog.Builder(
this);
2815 builder.setCancelable(
true);
2816 builder.setTitle(
"Choose Your File (*.db)");
2817 builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
2818 public void onClick(DialogInterface dialog,
int whichIn) {
2822 builder.setAdapter(simpleAdapter,
new DialogInterface.OnClickListener() {
2824 public void onClick(DialogInterface dialog,
final int which) {
2827 AlertDialog d2 =
new AlertDialog.Builder(
getActivity())
2828 .setCancelable(
false)
2829 .setTitle(
"Opening database...")
2830 .setMessage(
"Do you want to adjust colors now?\nThis can be done later under Optimize menu.")
2831 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
2832 public void onClick(DialogInterface dialog,
int whichIn) {
2836 .setNeutralButton(
"No",
new DialogInterface.OnClickListener() {
2837 public void onClick(DialogInterface dialog,
int whichIn) {
2842 d2.setCanceledOnTouchOutside(
false);
2848 final AlertDialog ad = builder.create();
2849 ad.setCanceledOnTouchOutside(
true);
2850 ad.setOnShowListener(
new OnShowListener()
2853 public void onShow(DialogInterface dialog)
2855 ListView lv = ad.getListView();
2856 ad.registerForContextMenu(lv);
2857 lv.setOnCreateContextMenuListener(
new OnCreateContextMenuListener() {
2860 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
2862 if (v.getId()==ad.getListView().getId()) {
2863 AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
2864 final int position = info.position;
2865 menu.setHeaderTitle(files[position]);
2866 menu.add(Menu.NONE, 0, 0,
"Rename").setOnMenuItemClickListener(
new OnMenuItemClickListener() {
2868 public boolean onMenuItemClick(MenuItem item) {
2869 AlertDialog.Builder builderRename =
new AlertDialog.Builder(
getActivity());
2870 builderRename.setCancelable(
false);
2871 builderRename.setTitle(
"RTAB-Map Database Name (*.db):");
2872 final EditText input =
new EditText(
getActivity());
2873 input.setInputType(InputType.TYPE_CLASS_TEXT);
2875 input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
2876 input.setSelectAllOnFocus(
true);
2878 builderRename.setView(input);
2879 builderRename.setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
2881 public void onClick(DialogInterface dialog,
int which)
2883 final String fileName = input.getText().toString();
2885 if(!fileName.isEmpty())
2887 File newFile =
new File(mWorkingDirectory + fileName +
".db");
2888 if(newFile.exists())
2890 AlertDialog d2 =
new AlertDialog.Builder(
getActivity())
2891 .setCancelable(
false)
2892 .setTitle(
"File Already Exists")
2893 .setMessage(String.format(
"Name %s already used, choose another name.", fileName))
2895 d2.setCanceledOnTouchOutside(
false);
2900 File from =
new File(mWorkingDirectory, files[position]);
2901 File to =
new File(mWorkingDirectory, fileName +
".db");
2904 long stamp = System.currentTimeMillis();
2905 if(stamp-mSavedStamp < 10000)
2908 Thread.sleep(10000 - (stamp-mSavedStamp));
2910 catch(InterruptedException
e){}
2922 AlertDialog alertToShow = builderRename.create();
2923 alertToShow.setCanceledOnTouchOutside(
false);
2924 alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
2929 menu.add(Menu.NONE, 1, 1,
"Delete").setOnMenuItemClickListener(
new OnMenuItemClickListener() {
2931 public boolean onMenuItemClick(MenuItem item) {
2932 DialogInterface.OnClickListener dialogClickListener =
new DialogInterface.OnClickListener() {
2934 public void onClick(DialogInterface dialog,
int which) {
2936 case DialogInterface.BUTTON_POSITIVE:
2937 Log.e(TAG, String.format(
"Yes delete %s!", files[position]));
2938 (
new File(mWorkingDirectory+files[position])).
delete();
2944 case DialogInterface.BUTTON_NEGATIVE:
2950 AlertDialog dialog =
new AlertDialog.Builder(
getActivity())
2951 .setCancelable(
false)
2952 .setTitle(String.format(
"Delete %s", files[position]))
2953 .setMessage(
"Are you sure?")
2954 .setPositiveButton(
"Yes", dialogClickListener)
2955 .setNegativeButton(
"No", dialogClickListener).create();
2956 dialog.setCanceledOnTouchOutside(
false);
2961 menu.add(Menu.NONE, 2, 2,
"Share").setOnMenuItemClickListener(
new OnMenuItemClickListener() {
2963 public boolean onMenuItemClick(MenuItem item) {
2971 File
f =
new File(mWorkingDirectory+files[position]);
2972 final int fileSizeMB = (int)f.length()/(1024 * 1024);
2973 Intent shareIntent =
new Intent();
2974 shareIntent.setAction(Intent.ACTION_SEND);
2975 shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
2976 Uri fileUri = FileProvider.getUriForFile(
getActivity(),
getActivity().getApplicationContext().getPackageName() +
".provider", f);
2977 shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
2978 shareIntent.setType(
"application/octet-stream");
2979 startActivity(Intent.createChooser(shareIntent, String.format(
"Sharing database \"%s\" (%d MB)...", files[position], fileSizeMB)));
2994 private void export(
final boolean isOBJ,
final boolean meshing,
final boolean regenerateCloud,
final boolean optimized,
final int optimizedMaxPolygons)
2996 final String extension = isOBJ?
".obj" :
".ply";
2999 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
3000 final String cloudVoxelSizeStr = sharedPref.getString(getString(R.string.pref_key_cloud_voxel), getString(R.string.pref_default_cloud_voxel));
3001 final float cloudVoxelSize = Float.parseFloat(cloudVoxelSizeStr);
3002 final int textureSize = isOBJ?Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_texture_size), getString(R.string.pref_default_texture_size))):0;
3003 final int textureCount = Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_texture_count), getString(R.string.pref_default_texture_count)));
3004 final int normalK = Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_normal_k), getString(R.string.pref_default_normal_k)));
3005 final float maxTextureDistance = Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_max_texture_distance), getString(R.string.pref_default_max_texture_distance)));
3006 final int minTextureClusterSize = Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_min_texture_cluster_size), getString(R.string.pref_default_min_texture_cluster_size)));
3007 final float optimizedVoxelSize = cloudVoxelSize;
3008 final int optimizedDepth = Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_opt_depth), getString(R.string.pref_default_opt_depth)));
3009 final float optimizedColorRadius = Float.parseFloat(sharedPref.getString(getString(R.string.pref_key_opt_color_radius), getString(R.string.pref_default_opt_color_radius)));
3010 final boolean optimizedCleanWhitePolygons = sharedPref.getBoolean(getString(R.string.pref_key_opt_clean_white),
Boolean.parseBoolean(getString(R.string.pref_default_opt_clean_white)));
3011 final int optimizedMinClusterSize = Integer.parseInt(sharedPref.getString(getString(R.string.pref_key_opt_min_cluster_size), getString(R.string.pref_default_opt_min_cluster_size)));
3012 final boolean blockRendering = sharedPref.getBoolean(getString(R.string.pref_key_block_render),
Boolean.parseBoolean(getString(R.string.pref_default_block_render)));
3015 mExportProgressDialog.setTitle(
"Exporting");
3016 mExportProgressDialog.setMessage(String.format(
"Please wait while preparing data to export..."));
3017 mExportProgressDialog.setProgress(0);
3019 final State previousState = mState;
3021 mExportProgressDialog.show();
3024 Thread exportThread =
new Thread(
new Runnable() {
3027 final long startTime = System.currentTimeMillis()/1000;
3040 optimizedMaxPolygons,
3041 optimizedColorRadius,
3042 optimizedCleanWhitePolygons,
3043 optimizedMinClusterSize,
3045 minTextureClusterSize,
3047 runOnUiThread(
new Runnable() {
3049 if(mExportProgressDialog.isShowing())
3053 if(!meshing && cloudVoxelSize>0.0
f)
3055 mToast.makeText(
getActivity(), String.format(
"Cloud assembled and voxelized at %s m.", cloudVoxelSizeStr), mToast.LENGTH_LONG).show();
3058 final long endTime = System.currentTimeMillis()/1000;
3060 if(endTime-startTime > 10)
3064 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
getActivity());
3065 boolean notifySound = sharedPref.getBoolean(getString(R.string.pref_key_notification_sound),
Boolean.parseBoolean(getString(R.string.pref_default_notification_sound)));
3066 Notification n =
new Notification.Builder(
getActivity())
3067 .setContentTitle(getString(R.string.app_name))
3068 .setContentText(
"Data generated and ready to be exported!")
3069 .setSmallIcon(R.drawable.ic_launcher)
3070 .setDefaults(notifySound?Notification.DEFAULT_SOUND:0)
3071 .setAutoCancel(
true).build();
3073 NotificationManager notificationManager =
3074 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
3076 notificationManager.notify(0, n);
3081 mSavedRenderingType = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2;
3084 mItemRenderingPointCloud.setChecked(
true);
3088 mItemRenderingMesh.setChecked(
true);
3092 mItemRenderingTextureMesh.setChecked(
true);
3094 if(!optimizedCleanWhitePolygons)
3096 mButtonLighting.setChecked(
true);
3101 if(mButtonCameraView.getSelectedItemPosition() == 0)
3105 if(mOpenedDatabasePath.isEmpty())
3113 mToast.makeText(
getActivity(), String.format(
"Exporting map failed!"), mToast.LENGTH_LONG).show();
3115 mExportProgressDialog.dismiss();
3119 mProgressDialog.dismiss();
3120 mToast.makeText(
getActivity(), String.format(
"Export canceled"), mToast.LENGTH_LONG).show();
3127 exportThread.start();
3132 AlertDialog.Builder builder =
new AlertDialog.Builder(
this);
3133 builder.setCancelable(
false);
3134 builder.setTitle(
"RTAB-Map Database Name (*.db):");
3135 final EditText input =
new EditText(
this);
3136 input.setInputType(InputType.TYPE_CLASS_TEXT);
3137 if(mOpenedDatabasePath.isEmpty())
3139 String
timeStamp =
new SimpleDateFormat(
"yyMMdd-HHmmss").format(mDateOnPause);
3140 input.setText(timeStamp);
3144 File
f =
new File(mOpenedDatabasePath);
3145 String name = f.getName();
3146 input.setText(name.substring(0,name.lastIndexOf(
".")));
3148 input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
3149 input.setSelectAllOnFocus(
true);
3151 builder.setView(input);
3152 builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
3154 public void onClick(DialogInterface dialog,
int which)
3159 builder.setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
3161 public void onClick(DialogInterface dialog,
int which)
3163 final String fileName = input.getText().toString();
3165 if(!fileName.isEmpty())
3167 File newFile =
new File(mWorkingDirectory + fileName +
".db");
3168 if(newFile.exists())
3170 AlertDialog d2 =
new AlertDialog.Builder(
getActivity())
3171 .setCancelable(
false)
3172 .setTitle(
"File Already Exists")
3173 .setMessage(
"Do you want to overwrite the existing file?")
3174 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
3175 public void onClick(DialogInterface dialog,
int which) {
3179 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
3180 public void onClick(DialogInterface dialog,
int which) {
3186 d2.setCanceledOnTouchOutside(
false);
3196 AlertDialog alertToShow = builder.create();
3197 alertToShow.setCanceledOnTouchOutside(
false);
3198 alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
3208 Intent mediaScanIntent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
3209 Uri contentUri = Uri.fromFile(
new File(docPath));
3210 mediaScanIntent.setData(contentUri);
3211 context.sendBroadcast(mediaScanIntent);
3216 final String newDatabasePath = mWorkingDirectory + fileName +
".db";
3217 final String newDatabasePathHuman = mWorkingDirectoryHuman + fileName +
".db";
3218 mProgressDialog.setTitle(
"Saving");
3219 if(mOpenedDatabasePath.equals(newDatabasePath))
3221 mProgressDialog.setMessage(String.format(
"Please wait while updating \"%s\"...", newDatabasePathHuman));
3225 mProgressDialog.setMessage(String.format(
"Please wait while saving \"%s\"...", newDatabasePathHuman));
3227 mProgressDialog.show();
3228 final State previousState = mState;
3230 Thread saveThread =
new Thread(
new Runnable() {
3233 runOnUiThread(
new Runnable() {
3236 if(mOpenedDatabasePath.equals(newDatabasePath))
3238 msg = String.format(
"Database \"%s\" updated.", newDatabasePathHuman);
3243 mSavedStamp = System.currentTimeMillis();
3244 msg = String.format(
"Database saved to \"%s\".", newDatabasePathHuman);
3250 PendingIntent pIntent = PendingIntent.getActivity(
getActivity(), (
int) System.currentTimeMillis(), intent, 0);
3251 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
getActivity());
3252 boolean notifySound = sharedPref.getBoolean(getString(R.string.pref_key_notification_sound),
Boolean.parseBoolean(getString(R.string.pref_default_notification_sound)));
3253 Notification n =
new Notification.Builder(
getActivity())
3254 .setContentTitle(getString(R.string.app_name))
3255 .setContentText(msg)
3256 .setSmallIcon(R.drawable.ic_launcher)
3257 .setContentIntent(pIntent)
3258 .setDefaults(notifySound?Notification.DEFAULT_SOUND:0)
3259 .setAutoCancel(
true).build();
3261 NotificationManager notificationManager =
3262 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
3264 notificationManager.notify(0, n);
3266 final File
f =
new File(newDatabasePath);
3267 final int fileSizeMB = (int)f.length()/(1024 * 1024);
3269 if(!mItemDataRecorderMode.isChecked())
3271 mOpenedDatabasePath = newDatabasePath;
3273 mProgressDialog.dismiss();
3276 AlertDialog d2 =
new AlertDialog.Builder(
getActivity())
3277 .setCancelable(
false)
3278 .setTitle(
"Database saved!")
3279 .setMessage(String.format(
"Database \"%s\" (%d MB) successfully saved on the SD-CARD!", newDatabasePathHuman, fileSizeMB))
3280 .setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
3281 public void onClick(DialogInterface dialog,
int which) {
3286 d2.setCanceledOnTouchOutside(
true);
3297 AlertDialog.Builder builder =
new AlertDialog.Builder(
this);
3298 builder.setTitle(
"Model Name:");
3299 final EditText input =
new EditText(
this);
3300 input.setInputType(InputType.TYPE_CLASS_TEXT);
3301 builder.setView(input);
3302 if(mOpenedDatabasePath.isEmpty())
3304 String
timeStamp =
new SimpleDateFormat(
"yyMMdd-HHmmss").format(mDateOnPause);
3305 input.setText(timeStamp);
3309 File
f =
new File(mOpenedDatabasePath);
3310 String name = f.getName();
3311 input.setText(name.substring(0,name.lastIndexOf(
".")));
3313 input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
3314 input.setSelectAllOnFocus(
true);
3316 builder.setCancelable(
false);
3317 builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
3319 public void onClick(DialogInterface dialog,
int which)
3325 builder.setPositiveButton(
"Ok",
new DialogInterface.OnClickListener() {
3327 public void onClick(DialogInterface dialog,
int which)
3329 final String fileName = input.getText().toString();
3331 if(!fileName.isEmpty())
3333 File newFile =
new File(mWorkingDirectory + RTABMAP_EXPORT_DIR + fileName +
".zip");
3334 if(newFile.exists())
3336 AlertDialog ad =
new AlertDialog.Builder(
getActivity())
3337 .setCancelable(
false)
3338 .setTitle(
"File Already Exists")
3339 .setMessage(
"Do you want to overwrite the existing file?")
3340 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
3341 public void onClick(DialogInterface dialog,
int which) {
3345 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
3346 public void onClick(DialogInterface dialog,
int which) {
3350 ad.setCanceledOnTouchOutside(
false);
3360 AlertDialog alertToShow = builder.create();
3361 alertToShow.setCanceledOnTouchOutside(
false);
3362 alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
3368 Log.i(TAG, String.format(
"Write exported mesh to \"%s\"", fileName));
3370 mProgressDialog.setTitle(
"Saving to sd-card");
3371 mProgressDialog.setMessage(String.format(
"Compressing the files..."));
3372 mProgressDialog.show();
3374 Thread workingThread =
new Thread(
new Runnable() {
3376 boolean success =
false;
3378 File tmpDir =
new File(mWorkingDirectory + RTABMAP_TMP_DIR);
3380 String[] fileNames =
Util.
loadFileList(mWorkingDirectory + RTABMAP_TMP_DIR,
false);
3381 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Deleting %d files in \"%s\"", fileNames.length, mWorkingDirectory + RTABMAP_TMP_DIR));
3382 for(
int i=0; i<fileNames.length; ++i)
3384 File
f =
new File(mWorkingDirectory + RTABMAP_TMP_DIR +
"/" + fileNames[i]);
3387 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Deleted \"%s\"", f.getPath()));
3391 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Failed deleting \"%s\"", f.getPath()));
3394 File exportDir =
new File(mWorkingDirectory + RTABMAP_EXPORT_DIR);
3397 final String pathHuman = mWorkingDirectoryHuman + RTABMAP_EXPORT_DIR + fileName +
".zip";
3398 final String zipOutput = mWorkingDirectory+RTABMAP_EXPORT_DIR+fileName+
".zip";
3402 if(fileNames.length > 0)
3404 String[] filesToZip =
new String[fileNames.length];
3405 for(
int i=0; i<fileNames.length; ++i)
3407 filesToZip[i] = mWorkingDirectory + RTABMAP_TMP_DIR +
"/" + fileNames[i];
3410 File toZIPFile =
new File(zipOutput);
3415 Util.
zip(filesToZip, zipOutput);
3418 catch(IOException
e)
3420 final String msg = e.getMessage();
3421 runOnUiThread(
new Runnable() {
3423 mToast.makeText(
getActivity(), String.format(
"Exporting mesh \"%s\" failed! Error=%s", pathHuman, msg), mToast.LENGTH_LONG).show();
3432 runOnUiThread(
new Runnable() {
3434 mProgressDialog.dismiss();
3436 final File
f =
new File(zipOutput);
3437 final int fileSizeMB = (int)f.length()/(1024 * 1024);
3440 .setCancelable(
false)
3441 .setTitle(
"Mesh Saved!")
3442 .setMessage(String.format(
"Mesh \"%s\" (%d MB) successfully exported on the SD-CARD! Share it?", pathHuman, fileSizeMB))
3443 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
3444 public void onClick(DialogInterface dialog,
int which) {
3446 Intent shareIntent =
new Intent();
3447 shareIntent.setAction(Intent.ACTION_SEND);
3448 shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(f));
3449 shareIntent.setType(
"application/zip");
3450 startActivity(Intent.createChooser(shareIntent,
"Sharing..."));
3455 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
3456 public void onClick(DialogInterface dialog,
int which) {
3460 d.setCanceledOnTouchOutside(
false);
3467 runOnUiThread(
new Runnable() {
3469 mProgressDialog.dismiss();
3470 mToast.makeText(
getActivity(), String.format(
"Exporting mesh \"%s\" failed! No files found in tmp directory!? Last export may have failed or have been canceled.", pathHuman), mToast.LENGTH_LONG).show();
3477 workingThread.start();
3482 mOpenedDatabasePath = mWorkingDirectory + fileName;
3484 Log.i(TAG,
"Open database " + mOpenedDatabasePath);
3486 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
getActivity());
3487 final boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory),
Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
3489 mProgressDialog.setTitle(
"Loading");
3490 mProgressDialog.setMessage(String.format(
"Opening database \"%s\"...", fileName));
3491 mProgressDialog.show();
3494 Thread openThread =
new Thread(
new Runnable() {
3498 final int status =
RTABMapLib.
openDatabase2(nativeApplication, mOpenedDatabasePath, tmpDatabase, databaseInMemory, optimize);
3500 runOnUiThread(
new Runnable() {
3505 mProgressDialog.dismiss();
3507 .setCancelable(
false)
3509 .setMessage(
"The map is loaded but optimization of the map's graph has " 3510 +
"failed, so the map cannot be shown. Change the Graph Optimizer approach used" 3511 +
" or enable/disable if the graph is optimized from graph " 3512 +
"end in \"Settings -> Mapping...\" and try opening again.")
3513 .setPositiveButton(
"Open Settings",
new DialogInterface.OnClickListener() {
3514 public void onClick(DialogInterface dialog,
int which) {
3516 startActivity(intent);
3519 .setNegativeButton(
"Close",
new DialogInterface.OnClickListener() {
3520 public void onClick(DialogInterface dialog,
int which) {
3523 d.setCanceledOnTouchOutside(
false);
3526 else if(status == -2)
3529 mProgressDialog.dismiss();
3531 .setCancelable(
false)
3533 .setMessage(
"Failed to open database: Out of memory! Try " 3534 +
"again after lowering Point Cloud Density in Settings.")
3535 .setPositiveButton(
"Open Settings",
new DialogInterface.OnClickListener() {
3536 public void onClick(DialogInterface dialog,
int which) {
3538 startActivity(intent);
3541 .setNegativeButton(
"Close",
new DialogInterface.OnClickListener() {
3542 public void onClick(DialogInterface dialog,
int which) {
3545 d.setCanceledOnTouchOutside(
false);
3550 if(status >= 1 && status<=3)
3552 mProgressDialog.dismiss();
3555 mToast.makeText(
getActivity(), String.format(
"Database loaded!"), mToast.LENGTH_LONG).show();
3557 else if(!mItemTrajectoryMode.isChecked())
3559 if(mButtonCameraView.getSelectedItemPosition() == 0)
3565 mProgressDialog.setTitle(
"Loading");
3566 mProgressDialog.setMessage(String.format(
"Database \"%s\" loaded. Please wait while rendering point clouds and meshes...", fileName));
3577 public void copy(File src, File
dst)
throws IOException {
3578 InputStream in =
new FileInputStream(src);
3579 OutputStream out =
new FileOutputStream(
dst);
3584 while ((len = in.read(buf)) > 0) {
3585 out.write(buf, 0, len);
3600 intent.putExtra(RTABMAP_AUTH_TOKEN_KEY, mAuthToken);
3601 intent.putExtra(RTABMAP_WORKING_DIR_KEY, mWorkingDirectory);
3603 if(mOpenedDatabasePath.isEmpty())
3605 intent.putExtra(RTABMAP_FILENAME_KEY,
new SimpleDateFormat(
"yyMMdd-HHmmss").format(mDateOnPause));
3609 File
f =
new File(mOpenedDatabasePath);
3610 String name = f.getName();
3611 intent.putExtra(RTABMAP_FILENAME_KEY, name.substring(0,name.lastIndexOf(
".")));
3614 startActivityForResult(intent, SKETCHFAB_ACTIVITY_CODE);
boolean mLastMagnetometerSet
void writeExportedFiles(final String fileName)
boolean mLastAccelerometerSet
static final String RTABMAP_EXPORT_DIR
GLM_FUNC_DECL T roll(detail::tquat< T, P > const &x)
static boolean DISABLE_LOG
static native void destroyNativeApplication(long nativeApplication)
static final int SKETCHFAB_ACTIVITY_CODE
static native void setMeshTriangleSize(long nativeApplication, int value)
MenuItem mItemRenderingTextureMesh
String mOpenedDatabasePath
static final String RTABMAP_TMP_DB
static native void setDepthFromMotion(long nativeApplication, boolean enabled)
static boolean hasPermission(Activity activity, String permission)
static final String RTABMAP_FILENAME_KEY
void updateCameraDriverSettings()
void onNothingSelected(AdapterView<?> parent)
MenuItem mItemPostProcessing
void updateProgressionCallback(final int count, final int max)
void onSensorChanged(SensorEvent event)
static native int openDatabase(long nativeApplication, String databasePath, boolean databaseInMemory, boolean optimize)
static final int MIN_TANGO_CORE_VERSION
static final int INTERNET_CODE
static native void setMinCloudDepth(long nativeApplication, float value)
ros::Time * timeStamp(M &m)
static native int openDatabase2(long nativeApplication, String databaseSource, String databasePath, boolean databaseInMemory, boolean optimize)
void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
static native void setLighting(long nativeApplication, boolean enabled)
static native boolean writeExportedMesh(long nativeApplication, String directory, String name)
void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results)
static native void setCameraColor(long nativeApplication, boolean enabled)
static native void setPausedMapping(long nativeApplication, boolean paused)
MenuItem mItemStatusVisibility
void setSelection(int position, boolean animate)
final int STATUS_TEXTS_POSE_INDEX
void onPanelClosed(int featureId, Menu menu)
void export(final boolean isOBJ, final boolean meshing, final boolean regenerateCloud, final boolean optimized, final int optimizedMaxPolygons)
MenuItem mItemRenderingPointCloud
GLM_FUNC_DECL genType e()
static native void setRawScanSaved(long nativeApplication, boolean enabled)
static native void setScreenRotation(long nativeApplication, int displayRotation, int cameraRotation)
final int STATUS_TEXTS_SIZE
static native void setFullResolution(long nativeApplication, boolean enabled)
ToggleButton mButtonLighting
static native boolean postExportation(long nativeApplication, boolean visualize)
void setProgressDialog(ProgressDialog progressDialog)
static void requestPermission(Activity activity, String permission)
GLM_FUNC_DECL T pitch(detail::tquat< T, P > const &x)
void onWindowFocusChanged(boolean hasFocus)
boolean isDepthSupported()
static native void setRenderingTextureDecimation(long nativeApplication, int value)
static native void setBackgroundColor(long nativeApplication, float gray)
LocationManager mLocationManager
static final long NOTOUCH_TIMEOUT
static void zip(String file, String zipFile)
void rtabmapInitEventCallback(final int status, final String msg)
static native void setDataRecorderMode(long nativeApplication, boolean enabled)
void updateStatsCallback(final int nodes, final int words, final int points, final int polygons, final float updateTime, final int loopClosureId, final int highestHypId, final int databaseMemoryUsed, final int inliers, final int matches, final int featuresExtracted, final float hypothesis, final int nodesDrawn, final float fps, final int rejected, final float rehearsalValue, final float optimizationMaxError, final float optimizationMaxErrorRatio, final float distanceTravelled, final int fastMovement, final int landmarkDetected, final float x, final float y, final float z, final float roll, final float pitch, final float yaw)
boolean mIsAREngineAvailable
static native void setLocalizationMode(long nativeApplication, boolean enabled)
void standardOptimization(final boolean withStandardMeshExport)
static final String EXTRA_KEY_PERMISSIONTYPE
static long nativeApplication
void onActivityResult(int requestCode, int resultCode, Intent data)
static native void setSmoothing(long nativeApplication, boolean enabled)
AlertDialog mMemoryWarningDialog
void resetNoTouchTimer(boolean showHud)
void updateTexts(String[] texts)
static native void setCloudDensityLevel(long nativeApplication, int value)
void onAccuracyChanged(Sensor sensor, int accuracy)
static native void setMaxCloudDepth(long nativeApplication, float value)
static native void setGridVisible(long nativeApplication, boolean visible)
static final String RTABMAP_OPENED_DB_PATH_KEY
boolean onOptionsItemSelected(MenuItem item)
SensorManager mSensorManager
static native void addEnvSensor(long nativeApplication, int type, float value)
static native void stopCamera(long nativeApplication)
static native boolean startCamera(long nativeApplication, IBinder binder, Context context, Activity activity, int driver)
static native void setGridRotation(long nativeApplication, float value)
MenuItem mItemDataRecorderMode
void closeVisualization()
GLM_FUNC_DECL genType pi()
void updateProgressionUI(int count, int max)
void setTextColor(float color)
void setCamera(ARCoreSharedCamera camera)
NDSpinner mButtonCameraView
void openDatabase(final String fileName, final boolean optimize)
static final String RTABMAP_WORKING_DIR_KEY
static native void setMeshRendering(long nativeApplication, boolean enabled, boolean withTexture)
MenuItem mItemTrajectoryMode
void cameraEventUI(int type, String key, String value)
void startCamera(final String message)
MenuItem mItemRenderingMesh
static native void setOdomCloudShown(long nativeApplication, boolean shown)
void onCreate(Bundle savedInstanceState)
static native void setGPS(long nativeApplication, double stamp, double longitude, double latitude, double altitude, double accuracy, double bearing)
void setAndroidOrientation()
static native void setGraphVisible(long nativeApplication, boolean visible)
void updateStatsUI(int loopClosureId, int inliers, int matches, int rejected, float optimizationMaxError, float optimizationMaxErrorRatio, boolean fastMovement, int landmarkDetected, String[] statusTexts)
static boolean shouldShowRequestPermissionRationale(Activity activity, String permission)
static native void setOrthoCropFactor(long nativeApplication, float value)
boolean mIsARCoreAvailable
static String[] loadFileList(String directory, final boolean databasesOnly)
RecoveryProgressState state
boolean CheckTangoCoreVersion(int minVersion)
void saveDatabase(String fileName)
static native void setPointSize(long nativeApplication, float value)
static native void setOnlineBlending(long nativeApplication, boolean enabled)
void updateState(State state)
static native boolean exportMesh(long nativeApplication, float cloudVoxelSize, boolean regenerateCloud, boolean meshing, int textureSize, int textureCount, int normalK, boolean optimized, float optimizedVoxelSize, int optimizedDepth, int optimizedMaxPolygons, float optimizedColorRadius, boolean optimizedCleanWhitePolygons, int optimizedMinClusterSize, float optimizedMaxTextureDistance, int optimizedMinTextureClusterSize, boolean blockRendering)
void copy(File src, File dst)
static final int CAMERA_CODE
String mMaxOptimizationError
Button mButtonShareOnSketchfab
static native boolean isBuiltWith(long nativeApplication, int cameraDriver)
static final String EXTRA_VALUE_ADF
LocationListener mLocationListener
static native long createNativeApplication(RTABMapActivity activity)
float[] mLastAccelerometer
static final int WRITE_EXTERNAL_STORAGE_CODE
GLM_FUNC_DECL genType max(genType const &x, genType const &y)
MenuItem mItemDebugVisibility
void stopDisconnectTimer()
Button mButtonSaveOnDevice
void rtabmapInitEventUI(int status, String msg)
boolean onMenuOpened(int featureId, Menu menu)
void setNavVisibility(boolean visible)
MenuItem mItemLocalizationMode
String mWorkingDirectoryHuman
GLM_FUNC_DECL T yaw(detail::tquat< T, P > const &x)
Button mButtonCloseVisualization
static final String RTABMAP_AUTH_TOKEN_KEY
static void refreshSystemMediaScanDataBase(Context context, String docPath)
RTABMapActivity getActivity()
static native void setTrajectoryMode(long nativeApplication, boolean enabled)
boolean[] mLastEnvSensorsSet
static native void setGraphOptimization(long nativeApplication, boolean enabled)
static native void setClusterRatio(long nativeApplication, float value)
static native void setMapCloudShown(long nativeApplication, boolean shown)
static native int postProcessing(long nativeApplication, int approach)
static final boolean bindTangoService(final Context context, ServiceConnection connection)
static native void cancelProcessing(long nativeApplication)
static final String TANGO_PACKAGE_NAME
Location mLastKnownLocation
float[] mLastMagnetometer
static final String RTABMAP_TMP_DIR
void isArEngineAvailable()
void setOffset(int offset)
static native void setMaxGainRadius(long nativeApplication, float value)
static native void save(long nativeApplication, String outputDatabasePath)
ToggleButton mButtonWireframe
boolean onCreateOptionsMenu(Menu menu)
STATE_VISUALIZING_WHILE_LOADING
ToggleButton mButtonBackfaceShown
void run(ClassLoader *loader)
static native void setBackfaceCulling(long nativeApplication, boolean enabled)
long mLastFastMovementNotificationStamp
static native void setWireframe(long nativeApplication, boolean enabled)
static native void onTouchEvent(long nativeApplication, int touchCount, int event0, float x0, float y0, float x1, float y1)
void setToast(Toast toast)
static native int setMappingParameter(long nativeApplication, String key, String value)
static final String RTABMAP_SDCARD_PATH
static native void setMeshAngleTolerance(long nativeApplication, float value)
static native void setAppendMode(long nativeApplication, boolean enabled)
void cameraEventCallback(final int type, final String key, final String value)
static native void setCamera(long nativeApplication, int cameraIndex)
static final String RTABMAP_TMP_FILENAME
static void launchPermissionSettings(Activity activity)
static native void setNodesFiltering(long nativeApplication, boolean enabled)