1 package com.introlab.rtabmap;
4 import java.io.FileInputStream;
5 import java.io.FileNotFoundException;
6 import java.io.FileOutputStream;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.OutputStream;
10 import java.lang.reflect.InvocationTargetException;
11 import java.lang.reflect.Method;
12 import java.text.SimpleDateFormat;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.Timer;
18 import java.util.TimerTask;
20 import android.Manifest;
21 import android.app.ActivityManager;
22 import android.app.ActivityManager.MemoryInfo;
23 import android.app.AlertDialog;
24 import android.app.Notification;
25 import android.app.NotificationManager;
26 import android.app.PendingIntent;
27 import android.app.ProgressDialog;
28 import android.content.ComponentName;
29 import android.content.ContentResolver;
30 import android.content.ContentValues;
31 import android.content.Context;
32 import android.content.DialogInterface;
33 import android.content.DialogInterface.OnShowListener;
34 import android.content.Intent;
35 import android.content.ServiceConnection;
36 import android.content.SharedPreferences;
37 import android.content.pm.ApplicationInfo;
38 import android.content.pm.PackageInfo;
39 import android.content.pm.PackageManager;
40 import android.content.pm.PackageManager.NameNotFoundException;
41 import android.database.Cursor;
42 import android.hardware.Camera;
43 import android.hardware.Sensor;
44 import android.hardware.SensorEvent;
45 import android.hardware.SensorEventListener;
46 import android.hardware.SensorManager;
47 import android.graphics.Matrix;
48 import android.graphics.Point;
49 import android.hardware.display.DisplayManager;
50 import android.location.Location;
51 import android.location.LocationListener;
52 import android.location.LocationManager;
53 import android.media.MediaScannerConnection;
54 import android.net.Uri;
55 import android.net.wifi.WifiInfo;
56 import android.net.wifi.WifiManager;
57 import android.opengl.GLSurfaceView;
58 import android.os.Bundle;
59 import android.os.Environment;
60 import android.os.Handler;
61 import android.os.IBinder;
62 import android.os.Message;
63 import android.preference.PreferenceManager;
64 import android.provider.MediaStore;
65 import android.provider.OpenableColumns;
66 import android.support.v4.app.FragmentActivity;
67 import android.support.v4.content.FileProvider;
68 import android.text.InputType;
69 import android.util.Log;
70 import android.util.TypedValue;
71 import android.view.ContextMenu;
72 import android.view.Display;
73 import android.view.GestureDetector;
74 import android.view.Menu;
75 import android.view.MenuItem;
76 import android.view.MenuItem.OnMenuItemClickListener;
77 import android.view.MenuInflater;
78 import android.view.MotionEvent;
79 import android.view.View;
80 import android.view.ContextMenu.ContextMenuInfo;
81 import android.view.View.OnClickListener;
82 import android.view.View.OnCreateContextMenuListener;
83 import android.view.View.OnTouchListener;
84 import android.view.WindowManager;
85 import android.view.inputmethod.EditorInfo;
86 import android.widget.AdapterView;
87 import android.widget.AdapterView.OnItemSelectedListener;
88 import android.widget.ArrayAdapter;
89 import android.widget.Button;
90 import android.widget.EditText;
91 import android.widget.ImageButton;
92 import android.widget.ListView;
93 import android.widget.NumberPicker;
94 import android.widget.RelativeLayout;
95 import android.widget.SeekBar;
96 import android.widget.SeekBar.OnSeekBarChangeListener;
97 import android.widget.Toast;
98 import android.widget.ToggleButton;
100 import com.google.ar.core.ArCoreApk;
101 import com.google.atap.tangoservice.Tango;
102 import com.huawei.hiar.AREnginesApk;
107 public class RTABMapActivity extends FragmentActivity implements OnClickListener, OnItemSelectedListener, SensorEventListener {
153 STATE_VISUALIZING_WHILE_LOADING
163 int mStatusBarHeight = 0;
164 int mActionBarHeight = 0;
166 ProgressDialog mProgressDialog;
167 ProgressDialog mExportProgressDialog;
230 Sensor mAccelerometer;
231 Sensor mMagnetometer;
232 Sensor mAmbientTemperature;
233 Sensor mAmbientLight;
234 Sensor mAmbientAirPressure;
235 Sensor mAmbientRelativeHumidity;
248 private float[]
mR =
new float[9];
262 GestureDetector mGesDetect =
null;
265 int mCameraDriver = 0;
270 boolean mCameraServiceConnectionUsed =
false;
271 ServiceConnection mCameraServiceConnection =
new ServiceConnection() {
272 public void onServiceConnected(ComponentName
name,
final IBinder service) {
273 Thread bindThread =
new Thread(
new Runnable() {
276 runOnUiThread(
new Runnable() {
278 mProgressDialog.dismiss();
279 if(!cameraStartSucess)
281 mToast.makeText(getApplicationContext(),
282 String.format(
"Failed to intialize Tango camera! RTAB-Map may not be built with Tango support."),
mToast.LENGTH_LONG).show();
283 if(mCameraServiceConnectionUsed)
286 getActivity().unbindService(mCameraServiceConnection);
288 mCameraServiceConnectionUsed =
false;
305 public void onServiceDisconnected(ComponentName
name) {
308 mToast.makeText(getApplicationContext(),
309 String.format(
"Tango disconnected!"),
mToast.LENGTH_LONG).show();
314 protected void onCreate(Bundle savedInstanceState) {
315 super.onCreate(savedInstanceState);
316 setTitle(
R.string.menu_name);
324 Display display = getWindowManager().getDefaultDisplay();
327 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
328 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
331 setContentView(
R.layout.activity_rtabmap);
336 mDecorView = getWindow().getDecorView();
343 mButtonStop = (ImageButton)findViewById(
R.id.stop_button);
377 ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(
this,
R.array.camera_view_array, android.R.layout.simple_spinner_item);
378 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
382 public boolean onTouch(View
v, MotionEvent event) {
393 public void onProgressChanged(SeekBar seekBar,
int progressValue,
boolean fromUser) {
399 public void onStartTrackingTouch(SeekBar seekBar) {
403 public void onStopTrackingTouch(SeekBar seekBar) {
410 mSeekBarGrid.setOnSeekBarChangeListener(
new OnSeekBarChangeListener() {
412 public void onProgressChanged(SeekBar seekBar,
int progressValue,
boolean fromUser) {
418 public void onStartTrackingTouch(SeekBar seekBar) {
422 public void onStopTrackingTouch(SeekBar seekBar) {
426 mToast = Toast.makeText(getApplicationContext(),
"", Toast.LENGTH_SHORT);
429 mGLView = (GLSurfaceView) findViewById(
R.id.gl_surface_view);
431 mGesDetect =
new GestureDetector(
this,
new DoubleTapGestureDetector());
434 mGLView.setEGLContextClientVersion(2);
435 mGLView.setEGLConfigChooser(8, 8, 8, 8, 24, 0);
436 mGLView.setOnTouchListener(
new OnTouchListener() {
438 public boolean onTouch(View
v, MotionEvent event) {
442 mGesDetect.onTouchEvent(event);
447 int pointCount =
event.getPointerCount();
448 if (pointCount == 1) {
452 event.getActionMasked(), normalizedX, normalizedY, 0.0f, 0.0f);
454 if (pointCount == 2) {
455 if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
456 int index =
event.getActionIndex() == 0 ? 1 : 0;
457 float normalizedX =
event.getX(index) /
mScreenSize.x;
458 float normalizedY =
event.getY(index) /
mScreenSize.y;
460 MotionEvent.ACTION_DOWN, normalizedX, normalizedY, 0.0f, 0.0f);
462 float normalizedX0 =
event.getX(0) /
mScreenSize.x;
463 float normalizedY0 =
event.getY(0) /
mScreenSize.y;
464 float normalizedX1 =
event.getX(1) /
mScreenSize.x;
465 float normalizedY1 =
event.getY(1) /
mScreenSize.y;
467 normalizedX0, normalizedY0, normalizedX1, normalizedY1);
478 mProgressDialog =
new ProgressDialog(
this);
479 mProgressDialog.setCanceledOnTouchOutside(
false);
484 mExportProgressDialog =
new ProgressDialog(
this);
485 mExportProgressDialog.setCanceledOnTouchOutside(
false);
486 mExportProgressDialog.setCancelable(
false);
487 mExportProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
488 mExportProgressDialog.setProgressNumberFormat(
null);
489 mExportProgressDialog.setProgressPercentFormat(
null);
490 mExportProgressDialog.setButton(DialogInterface.BUTTON_NEGATIVE,
"Cancel",
new DialogInterface.OnClickListener() {
492 public void onClick(DialogInterface dialog, int which) {
493 RTABMapLib.cancelProcessing(nativeApplication);
495 mProgressDialog.setTitle(
"");
496 mProgressDialog.setMessage(String.format(
"Cancelling..."));
497 mProgressDialog.show();
508 int targetSdkVersion= 0;
510 ApplicationInfo
app = this.getPackageManager().getApplicationInfo(
"com.introlab.rtabmap", 0);
511 targetSdkVersion =
app.targetSdkVersion;
512 }
catch (NameNotFoundException
e) {
516 if(Environment.getExternalStorageState().compareTo(Environment.MEDIA_MOUNTED)==0 &&
520 if(targetSdkVersion < 30)
522 extStore = Environment.getExternalStorageDirectory();
526 extStore =
getActivity().getExternalFilesDirs(
null)[0];
529 mWorkingDirectory = extStore.getAbsolutePath() +
"/" + getString(
R.string.app_name) +
"/";
537 mToast.makeText(getApplicationContext(),
538 String.format(
"Failed to get external storage path (state=%s). Saving disabled.",
539 Environment.getExternalStorageState()),
mToast.LENGTH_LONG).show();
542 DisplayManager displayManager = (DisplayManager) getSystemService(DISPLAY_SERVICE);
543 if (displayManager !=
null) {
544 displayManager.registerDisplayListener(
new DisplayManager.DisplayListener() {
546 public void onDisplayAdded(
int displayId) {
551 public void onDisplayChanged(
int displayId) {
552 synchronized (
this) {
554 Display display = getWindowManager().getDefaultDisplay();
560 public void onDisplayRemoved(
int displayId) {}
565 mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
569 public void onLocationChanged(Location location) {
571 double stamp = location.getTime()/1000.0;
572 if(!
DISABLE_LOG) Log.d(
TAG, String.format(
"GPS received at %f (%d)", stamp, location.getTime()));
576 (
double)location.getLongitude(),
577 (
double)location.getLatitude(),
578 (
double)location.getAltitude(),
579 (
double)location.getAccuracy(),
583 public void onStatusChanged(String provider,
int status, Bundle extras) {}
585 public void onProviderEnabled(String provider) {}
587 public void onProviderDisabled(String provider) {}
590 mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
591 mAccelerometer =
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
592 mMagnetometer =
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
593 mAmbientTemperature =
mSensorManager.getDefaultSensor(Sensor.TYPE_AMBIENT_TEMPERATURE);
594 mAmbientLight =
mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
595 mAmbientAirPressure =
mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
596 mAmbientRelativeHumidity =
mSensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY);
597 float []
values = {1,0,0,0,0,1,0,-1,0};
599 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
603 DISABLE_LOG = !( 0 != ( getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE ) );
605 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
606 String cameraDriverStr = sharedPref.getString(getString(
R.string.pref_key_camera_driver), getString(
R.string.pref_default_camera_driver));
607 mCameraDriver = Integer.parseInt(cameraDriverStr);
612 if (!PermissionHelper.hasPermission(
this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
613 PermissionHelper.requestPermission(
this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
618 Intent intent = getIntent();
619 String
action = intent.getAction();
620 String
type = intent.getType();
622 if (Intent.ACTION_SEND.equals(action) &&
type !=
null) {
623 if (
"application/octet-stream".equals(
type)) {
624 Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
625 if (imageUri !=
null) {
627 Log.i(
TAG,
"Intent received: " + imageUri.getPath() +
" Name:" + fileName);
628 if(fileName.endsWith(
".db"))
633 mToast.makeText(
this, fileName +
" already exists in RTAB-Map's library! Cannot be copied.",
mToast.LENGTH_LONG).show();
637 copy(imageUri, file);
643 }
else if (Intent.ACTION_SEND_MULTIPLE.equals(action) &&
type !=
null) {
644 if (
type.startsWith(
"application/")) {
645 ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
646 if (imageUris !=
null) {
647 boolean added =
false;
648 for(Uri imageUri: imageUris)
651 Log.i(
TAG,
"Intent received: " + imageUri.getPath() +
" Name:" + fileName);
652 if(fileName.endsWith(
".db"))
657 copy(imageUri, file);
662 Log.e(
TAG, fileName +
" already exists in RTAB-Map's library! Cannot be copied.");
679 public void copy(File src, File
dst)
throws IOException {
680 InputStream in =
new FileInputStream(src);
681 OutputStream
out =
new FileOutputStream(
dst);
684 byte[] buf =
new byte[1024];
686 while ((
len = in.read(buf)) > 0) {
693 public void copy(Uri uri, File file)
697 in = getApplicationContext().getContentResolver().openInputStream(uri);
699 OutputStream
out =
new FileOutputStream(
file);
700 byte[] buf =
new byte[1024];
702 while ((
len = in.read(buf)) > 0) {
707 }
catch (IOException
e) {
708 Log.e(TAG,
e.getMessage());
714 if (uri.getScheme().equals(
"content")) {
715 Cursor cursor = getContentResolver().query(uri,
null,
null,
null,
null);
717 if (cursor !=
null && cursor.moveToFirst()) {
718 result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
726 int cut =
result.lastIndexOf(
'/');
738 Log.i(TAG,
"postCreate()");
741 if(files.length == 0)
743 mButtonLibrary.setVisibility(View.INVISIBLE);
749 Log.i(TAG, String.format(
"updateCameraDriverSettings() mCameraDriver=%d RTABMapLib.isBuiltWith(%d)=%d", mCameraDriver, mCameraDriver,
RTABMapLib.
isBuiltWith(nativeApplication, mCameraDriver)?1:0));
751 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
752 String cameraDriverStr = sharedPref.getString(getString(
R.string.pref_key_camera_driver), getString(
R.string.pref_default_camera_driver));
753 mCameraDriver = Integer.parseInt(cameraDriverStr);
755 if(mCameraDriver == -1)
759 SharedPreferences.Editor editor = sharedPref.edit();
760 editor.putString(getString(
R.string.pref_key_camera_driver),
"0");
764 if(mCameraDriver == 0 && (!CheckTangoCoreVersion(MIN_TANGO_CORE_VERSION) || !
RTABMapLib.
isBuiltWith(nativeApplication, 0)))
768 SharedPreferences.Editor editor = sharedPref.edit();
769 editor.putString(getString(
R.string.pref_key_camera_driver),
"2");
772 else if(mIsARCoreAvailable)
774 SharedPreferences.Editor editor = sharedPref.edit();
775 editor.putString(getString(
R.string.pref_key_camera_driver),
"3");
779 else if(((mCameraDriver == 1 && (!
RTABMapLib.
isBuiltWith(nativeApplication, 0) || !mIsARCoreAvailable)) ||
780 (mCameraDriver == 3 && !mIsARCoreAvailable)))
784 SharedPreferences.Editor editor = sharedPref.edit();
785 editor.putString(getString(
R.string.pref_key_camera_driver),
"0");
790 SharedPreferences.Editor editor = sharedPref.edit();
791 editor.putString(getString(
R.string.pref_key_camera_driver),
"2");
795 else if(mCameraDriver == 2 && (!mIsAREngineAvailable || !
RTABMapLib.
isBuiltWith(nativeApplication, 2)))
799 SharedPreferences.Editor editor = sharedPref.edit();
800 editor.putString(getString(
R.string.pref_key_camera_driver),
"0");
803 else if(mIsARCoreAvailable)
805 SharedPreferences.Editor editor = sharedPref.edit();
806 editor.putString(getString(
R.string.pref_key_camera_driver),
"3");
813 ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(
this);
814 if (availability.isTransient()) {
816 new Handler().postDelayed(
new Runnable() {
823 if (availability.isSupported()) {
824 Log.i(TAG,
"ARCore supported");
825 mIsARCoreAvailable =
true;
826 updateCameraDriverSettings();
828 Log.i(TAG,
"ARCore supported");
829 mIsARCoreAvailable =
false;
830 updateCameraDriverSettings();
836 AREnginesApk.ARAvailability availability = AREnginesApk.checkAvailability(
this);
837 if (availability.isTransient()) {
839 new Handler().postDelayed(
new Runnable() {
842 isArEngineAvailable();
846 if (availability.isSupported()) {
847 Log.i(TAG,
"AREngine supported");
848 mIsAREngineAvailable =
true;
849 updateCameraDriverSettings();
851 Log.i(TAG,
"AREngine not supported");
852 mIsAREngineAvailable =
false;
853 updateCameraDriverSettings();
856 catch(UnsatisfiedLinkError
e)
858 Log.i(TAG,
"AREngine not supported");
859 mIsAREngineAvailable =
false;
868 if(!DISABLE_LOG) Log.d(TAG,
"onDestroy()");
870 synchronized (
this) {
872 nativeApplication = 0;
878 if(event.sensor == mAccelerometer || event.sensor == mMagnetometer)
880 if (event.sensor == mAccelerometer) {
881 System.arraycopy(event.values, 0, mLastAccelerometer, 0, event.values.length);
882 mLastAccelerometerSet =
true;
883 }
else if (event.sensor == mMagnetometer) {
884 System.arraycopy(event.values, 0, mLastMagnetometer, 0, event.values.length);
885 mLastMagnetometerSet =
true;
887 if (mLastAccelerometerSet && mLastMagnetometerSet) {
888 SensorManager.getRotationMatrix(mR,
null, mLastAccelerometer, mLastMagnetometer);
890 mNewR.setConcat(mRMat, mDeviceToCamera) ;
892 SensorManager.getOrientation(mR, mOrientation);
893 mCompassDeg = mOrientation[0] * 180.0f/(
float)Math.PI;
896 mCompassDeg += 360.0f;
900 else if(event.sensor == mAmbientTemperature)
902 mLastEnvSensors[1] =
event.values[0];
903 mLastEnvSensorsSet[1] =
true;
906 else if(event.sensor == mAmbientAirPressure)
908 mLastEnvSensors[2] =
event.values[0];
909 mLastEnvSensorsSet[2] =
true;
912 else if(event.sensor == mAmbientLight)
914 mLastEnvSensors[3] =
event.values[0];
915 mLastEnvSensorsSet[3] =
true;
918 else if(event.sensor == mAmbientRelativeHumidity)
920 mLastEnvSensors[4] =
event.values[0];
921 mLastEnvSensorsSet[4] =
true;
934 int resourceId = getResources().getIdentifier(
"status_bar_height",
"dimen",
"android");
935 if (resourceId > 0) {
936 result = getResources().getDimensionPixelSize(resourceId);
942 TypedValue tv =
new TypedValue();
943 if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv,
true))
945 result = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
954 super.onWindowFocusChanged(hasFocus);
958 mRenderer.
setOffset(!hasFocus?-mStatusBarHeight:0);
964 int newVis = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
965 | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
966 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
968 newVis |= View.SYSTEM_UI_FLAG_LOW_PROFILE
969 | View.SYSTEM_UI_FLAG_FULLSCREEN
970 | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
971 | View.SYSTEM_UI_FLAG_IMMERSIVE;
972 mRenderer.
setOffset(!hasWindowFocus()?-mStatusBarHeight:0);
976 mRenderer.
setOffset(-mStatusBarHeight-mActionBarHeight);
980 mDecorView.setSystemUiVisibility(newVis);
986 if (requestCode == Tango.TANGO_INTENT_ACTIVITYCODE) {
988 if (resultCode == RESULT_CANCELED) {
989 mToast.makeText(
this,
"Motion Tracking Permissions Required!", mToast.LENGTH_SHORT).show();
992 else if (requestCode == SKETCHFAB_ACTIVITY_CODE) {
994 if (resultCode == RESULT_OK) {
995 mAuthToken =
data.getStringExtra(RTABMAP_AUTH_TOKEN_KEY);
1003 return super.onMenuOpened(featureId, menu);
1008 mMenuOpened =
false;
1014 Date
t =
new Date();
1015 boolean doubleBack =
t.getTime() - mBackClickedTime.getTime() < 3500;
1016 mBackClickedTime =
t;
1029 super.onBackPressed();
1033 mToast.makeText(
this,
"Press Back once more to exit", mToast.LENGTH_LONG).show();
1038 closeVisualization();
1047 stopDisconnectTimer();
1049 if(!DISABLE_LOG) Log.i(TAG,
"onPause()");
1061 mLocationManager.removeUpdates(mLocationListener);
1062 mSensorManager.unregisterListener(
this);
1063 mLastAccelerometerSet =
false;
1064 mLastMagnetometerSet=
false;
1065 mLastEnvSensorsSet[0] = mLastEnvSensorsSet[1]= mLastEnvSensorsSet[2]= mLastEnvSensorsSet[3]= mLastEnvSensorsSet[4]=
false;
1070 mOnPauseStamp = System.currentTimeMillis()/1000;
1078 Log.i(TAG,
"update preferences...");
1079 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1080 mUpdateRate = sharedPref.getString(getString(
R.string.pref_key_update_rate), getString(
R.string.pref_default_update_rate));
1081 String maxSpeed = sharedPref.getString(getString(
R.string.pref_key_max_speed), getString(
R.string.pref_default_max_speed));
1082 mTimeThr = sharedPref.getString(getString(
R.string.pref_key_time_thr), getString(
R.string.pref_default_time_thr));
1083 String memThr = sharedPref.getString(getString(
R.string.pref_key_mem_thr), getString(
R.string.pref_default_mem_thr));
1084 mLoopThr = sharedPref.getString(getString(
R.string.pref_key_loop_thr), getString(
R.string.pref_default_loop_thr));
1085 String simThr = sharedPref.getString(getString(
R.string.pref_key_sim_thr), getString(
R.string.pref_default_sim_thr));
1086 mMinInliers = sharedPref.getString(getString(
R.string.pref_key_min_inliers), getString(
R.string.pref_default_min_inliers));
1087 mMaxOptimizationError = sharedPref.getString(getString(
R.string.pref_key_opt_error), getString(
R.string.pref_default_opt_error));
1088 float maxOptimizationError =
Float.parseFloat(mMaxOptimizationError);
1089 if(maxOptimizationError >0 && maxOptimizationError<1)
1091 Log.w(TAG,
"Migration of " + getString(
R.string.pref_key_opt_error) +
" from " + mMaxOptimizationError +
" to " + getString(
R.string.pref_default_opt_error)) ;
1092 SharedPreferences.Editor editor = sharedPref.edit();
1093 editor.putString(getString(
R.string.pref_key_opt_error), getString(
R.string.pref_default_opt_error));
1095 mMaxOptimizationError = getString(
R.string.pref_default_opt_error);
1097 mMaxFeatures = sharedPref.getString(getString(
R.string.pref_key_features_voc), getString(
R.string.pref_default_features_voc));
1098 String maxFeaturesLoop = sharedPref.getString(getString(
R.string.pref_key_features), getString(
R.string.pref_default_features));
1099 String featureType = sharedPref.getString(getString(
R.string.pref_key_features_type), getString(
R.string.pref_default_features_type));
1100 boolean keepAllDb = sharedPref.getBoolean(getString(
R.string.pref_key_keep_all_db),
Boolean.parseBoolean(getString(
R.string.pref_default_keep_all_db)));
1101 boolean optimizeFromGraphEnd = sharedPref.getBoolean(getString(
R.string.pref_key_optimize_end),
Boolean.parseBoolean(getString(
R.string.pref_default_optimize_end)));
1102 String optimizer = sharedPref.getString(getString(
R.string.pref_key_optimizer), getString(
R.string.pref_default_optimizer));
1103 String markerDetection = sharedPref.getString(getString(
R.string.pref_key_marker_detection), getString(
R.string.pref_default_marker_detection));
1104 String markerDetectionDepthError = sharedPref.getString(getString(
R.string.pref_key_marker_detection_depth_error), getString(
R.string.pref_default_marker_detection_depth_error));
1105 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)));
1108 mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListener);
1109 mSensorManager.registerListener(
this, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
1110 mSensorManager.registerListener(
this, mMagnetometer, SensorManager.SENSOR_DELAY_UI);
1112 mEnvSensorsSaved = sharedPref.getBoolean(getString(
R.string.pref_key_env_sensors_saved),
Boolean.parseBoolean(getString(
R.string.pref_default_env_sensors_saved)));
1113 if(mEnvSensorsSaved)
1115 mSensorManager.registerListener(
this, mAmbientTemperature, SensorManager.SENSOR_DELAY_NORMAL);
1116 mSensorManager.registerListener(
this, mAmbientAirPressure, SensorManager.SENSOR_DELAY_NORMAL);
1117 mSensorManager.registerListener(
this, mAmbientLight, SensorManager.SENSOR_DELAY_NORMAL);
1118 mSensorManager.registerListener(
this, mAmbientRelativeHumidity, SensorManager.SENSOR_DELAY_NORMAL);
1119 mEnvSensorsTimer.schedule(
new TimerTask() {
1123 WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
1125 if(wifiInfo !=
null && (dbm = wifiInfo.getRssi()) > -127)
1127 mLastEnvSensors[0] = (
float)dbm;
1128 mLastEnvSensorsSet[0] =
true;
1136 Log.i(TAG,
"set mapping parameters");
1137 RTABMapLib.
setOnlineBlending(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_blending),
Boolean.parseBoolean(getString(
R.string.pref_default_blending))));
1138 RTABMapLib.
setNodesFiltering(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_nodes_filtering),
Boolean.parseBoolean(getString(
R.string.pref_default_nodes_filtering))));
1139 RTABMapLib.
setRawScanSaved(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_raw_scan_saved),
Boolean.parseBoolean(getString(
R.string.pref_default_raw_scan_saved))));
1140 RTABMapLib.
setFullResolution(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_resolution),
Boolean.parseBoolean(getString(
R.string.pref_default_resolution))));
1141 RTABMapLib.
setSmoothing(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_smoothing),
Boolean.parseBoolean(getString(
R.string.pref_default_smoothing))));
1142 RTABMapLib.
setDepthFromMotion(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_depth_from_motion),
Boolean.parseBoolean(getString(
R.string.pref_default_depth_from_motion))));
1143 RTABMapLib.
setCameraColor(nativeApplication, !sharedPref.getBoolean(getString(
R.string.pref_key_fisheye),
Boolean.parseBoolean(getString(
R.string.pref_default_fisheye))));
1144 RTABMapLib.
setAppendMode(nativeApplication, sharedPref.getBoolean(getString(
R.string.pref_key_append),
Boolean.parseBoolean(getString(
R.string.pref_default_append))));
1161 if(Integer.parseInt(markerDetection) == -1)
1173 Log.i(TAG,
"set exporting parameters...");
1174 RTABMapLib.
setCloudDensityLevel(nativeApplication, Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_density), getString(
R.string.pref_default_density))));
1175 RTABMapLib.
setMaxCloudDepth(nativeApplication,
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_depth), getString(
R.string.pref_default_depth))));
1176 RTABMapLib.
setMinCloudDepth(nativeApplication,
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_min_depth), getString(
R.string.pref_default_min_depth))));
1177 RTABMapLib.
setPointSize(nativeApplication,
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_point_size), getString(
R.string.pref_default_point_size))));
1179 RTABMapLib.
setMeshTriangleSize(nativeApplication, Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_triangle), getString(
R.string.pref_default_triangle))));
1180 float bgColor =
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_background_color), getString(
R.string.pref_default_background_color)));
1184 Log.i(TAG,
"set rendering parameters...");
1185 RTABMapLib.
setClusterRatio(nativeApplication,
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_cluster_ratio), getString(
R.string.pref_default_cluster_ratio))));
1186 RTABMapLib.
setMaxGainRadius(nativeApplication,
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_gain_max_radius), getString(
R.string.pref_default_gain_max_radius))));
1187 RTABMapLib.
setRenderingTextureDecimation(nativeApplication, Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_rendering_texture_decimation), getString(
R.string.pref_default_rendering_texture_decimation))));
1189 if(mItemRenderingPointCloud !=
null)
1191 int renderingType = sharedPref.getInt(getString(
R.string.pref_key_rendering), Integer.parseInt(getString(
R.string.pref_default_rendering)));
1192 if(renderingType == 0)
1194 mItemRenderingPointCloud.setChecked(
true);
1196 else if(renderingType == 1)
1198 mItemRenderingMesh.setChecked(
true);
1202 mItemRenderingTextureMesh.setChecked(
true);
1206 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
1207 mItemRenderingTextureMesh.isChecked());
1209 mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE);
1214 Log.e(TAG,
"Error parsing preferences: " +
e.getMessage());
1215 mToast.makeText(
this, String.format(
"Error parsing preferences: "+
e.getMessage()), mToast.LENGTH_LONG).show();
1223 setAndroidOrientation();
1225 updateCameraDriverSettings();
1226 updatePreferences();
1230 String message =
new String();
1233 if(System.currentTimeMillis()/1000 - mOnPauseStamp < 1)
1235 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.");
1239 message = String.format(
"Hold Tight! Initializing Camera Service...");
1241 mToast.makeText(
this,
"Mapping is paused!", mToast.LENGTH_LONG).show();
1245 message = String.format(
"Hold Tight! Initializing Camera Service...\nTip: If the camera is still drifting just after the mapping has started, do \"Reset\".");
1247 startCamera(message);
1251 if(!DISABLE_LOG) Log.i(TAG, String.format(
"onResume()"));
1258 switch (requestCode) {
1261 if (
results.length > 0 &&
results[0] == PackageManager.PERMISSION_GRANTED) {
1268 Toast.makeText(
this,
"Storage read/write permissions are needed to run this application", Toast.LENGTH_LONG).show();
1277 if (
results.length > 0 &&
results[0] == PackageManager.PERMISSION_GRANTED) {
1279 startCamera(String.format(
"Hold Tight! Initializing Camera Service...\n"
1280 +
"Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
1282 Toast.makeText(
this,
"Camera permission is needed for scanning and motion tracking.", Toast.LENGTH_LONG).show();
1290 if (
results.length > 0 &&
results[0] == PackageManager.PERMISSION_GRANTED) {
1293 Toast.makeText(
this,
"Internet permission is needed to share scans.", Toast.LENGTH_LONG).show();
1312 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1313 String cameraDriverStr = sharedPref.getString(getString(
R.string.pref_key_camera_driver), getString(
R.string.pref_default_camera_driver));
1314 final boolean depthFromMotion = sharedPref.getBoolean(getString(
R.string.pref_key_depth_from_motion),
Boolean.parseBoolean(getString(
R.string.pref_default_depth_from_motion)));
1315 mCameraDriver = Integer.parseInt(cameraDriverStr);
1317 Log.i(TAG, String.format(
"startCamera() driver=%d", mCameraDriver));
1318 if(mCameraDriver == 0)
1321 if (!CheckTangoCoreVersion(MIN_TANGO_CORE_VERSION)) {
1322 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();
1326 if (!Tango.hasPermission(
this, Tango.PERMISSIONTYPE_MOTION_TRACKING)) {
1327 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Asking for motion tracking permission"));
1328 startActivityForResult(
1329 Tango.getRequestPermissionIntent(Tango.PERMISSIONTYPE_MOTION_TRACKING),
1330 Tango.TANGO_INTENT_ACTIVITYCODE);
1336 if(mCameraServiceConnectionUsed)
1338 mProgressDialog.setTitle(
"");
1339 mProgressDialog.setMessage(message);
1340 mProgressDialog.show();
1341 resetNoTouchTimer(
true);
1347 mToast.makeText(
this,
"Current camera driver selected is Tango, but Tango service binding failed. Abort scanning...", mToast.LENGTH_LONG).show();
1351 else if(mCameraDriver == 1 || mCameraDriver == 2 || mCameraDriver == 3)
1353 if((mCameraDriver == 1 || mCameraDriver == 3) && !mIsARCoreAvailable)
1355 mToast.makeText(
this,
"ARCore not supported on this phone! Cannot start a new scan.", mToast.LENGTH_LONG).show();
1358 if(mCameraDriver == 2 && !mIsAREngineAvailable)
1360 mToast.makeText(
this,
"AREngine not supported on this phone! Cannot start a new scan.", mToast.LENGTH_LONG).show();
1365 if(mCameraDriver==1 && !mItemRenderingPointCloud.isChecked())
1367 mItemRenderingPointCloud.setChecked(
true);
1369 Thread bindThread =
new Thread(
new Runnable() {
1372 if(mCameraDriver==1 && !depthFromMotion)
1376 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
1377 mItemRenderingTextureMesh.isChecked());
1379 final boolean cameraStartSucess =
RTABMapLib.
startCamera(nativeApplication,
null, getApplicationContext(), getActivity(), mCameraDriver);
1380 runOnUiThread(
new Runnable() {
1382 boolean localSuccess = cameraStartSucess;
1383 if(cameraStartSucess && mCameraDriver == 3)
1385 synchronized (
this) {
1386 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
1387 String arCoreLocalizationFiltering = sharedPref.getString(getString(
R.string.pref_key_arcore_localization_filtering_speed), getString(
R.string.pref_default_arcore_localization_filtering_speed));
1390 mProgressDialog.setTitle(
"");
1391 mProgressDialog.setMessage(message);
1392 mProgressDialog.show();
1395 mToast.makeText(getActivity(),
"Current camera driver selected is ARCore Java, but initialization failed. Abort scanning...", mToast.LENGTH_LONG).show();
1396 mArCoreCamera =
null;
1397 localSuccess =
false;
1404 mItemRenderingPointCloud.setChecked(
true);
1406 mToast.makeText(getApplicationContext(),
"Depth camera not found, only poses and RGB images can be recorded.", mToast.LENGTH_LONG).show();
1412 mProgressDialog.dismiss();
1415 mToast.makeText(getApplicationContext(),
1416 String.format(
"Failed to intialize Camera!"), mToast.LENGTH_LONG).show();
1422 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();
1438 mToast.makeText(
this,
"Supported camera driver not found! Cannot start a new scan.", mToast.LENGTH_LONG).show();
1444 if(!DISABLE_LOG) Log.i(TAG, String.format(
"called setCamera(type=%d);",
type));
1447 long freeMemory = getFreeMemory();
1448 mStatusTexts[1] = getString(
R.string.memory)+String.valueOf(mFreeMemoryOnStart>freeMemory?mFreeMemoryOnStart-freeMemory:0);
1449 mStatusTexts[2] = getString(
R.string.free_memory)+String.valueOf(freeMemory);
1450 updateStatusTexts();
1454 mSeekBarOrthoCut.setVisibility(
type!=3?View.INVISIBLE:View.VISIBLE);
1455 mSeekBarGrid.setVisibility(mSeekBarGrid.isEnabled() &&
type==3?View.VISIBLE:View.INVISIBLE);
1458 mSeekBarOrthoCut.setMax(120);
1459 mSeekBarOrthoCut.setProgress(80);
1466 switch (
v.getId()) {
1467 case R.id.gl_surface_view:
1469 case R.id.start_button:
1472 case R.id.stop_button:
1482 case R.id.light_button:
1485 case R.id.backface_button:
1488 case R.id.wireframe_button:
1491 case R.id.close_visualization_button:
1492 closeVisualization();
1495 case R.id.button_saveOnDevice:
1498 case R.id.button_shareToSketchfab:
1501 case R.id.button_library:
1504 case R.id.button_new_scan:
1510 resetNoTouchTimer();
1515 if(mSavedRenderingType==0)
1517 mItemRenderingPointCloud.setChecked(
true);
1519 else if(mSavedRenderingType==1)
1521 mItemRenderingMesh.setChecked(
true);
1525 mItemRenderingTextureMesh.setChecked(
true);
1532 resetNoTouchTimer();
1536 resetNoTouchTimer();
1540 Display display = getWindowManager().getDefaultDisplay();
1541 Camera.CameraInfo colorCameraInfo =
new Camera.CameraInfo();
1542 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1543 boolean fisheye = sharedPref.getBoolean(getString(
R.string.pref_key_fisheye),
Boolean.parseBoolean(getString(
R.string.pref_default_fisheye)));
1544 Camera.getCameraInfo(fisheye?1:0, colorCameraInfo);
1548 class DoubleTapGestureDetector
extends GestureDetector.SimpleOnGestureListener {
1551 public boolean onDoubleTap(MotionEvent event) {
1552 if(!DISABLE_LOG) Log.i(TAG,
"onDoubleTap");
1553 float normalizedX =
event.getX(0) / mScreenSize.x;
1554 float normalizedY =
event.getY(0) / mScreenSize.y;
1555 RTABMapLib.
onTouchEvent(nativeApplication, 3, event.getActionMasked(), normalizedX, normalizedY, 0.0f, 0.0f);
1559 public boolean onSingleTapConfirmed(MotionEvent event) {
1560 if(!DISABLE_LOG) Log.i(TAG,
"onSingleTapConfirmed");
1563 notouchHandler.removeCallbacks(notouchCallback);
1564 notouchHandler.postDelayed(notouchCallback, 0);
1568 resetNoTouchTimer(
true);
1576 if(!DISABLE_LOG) Log.i(TAG,
"called onCreateOptionsMenu;");
1578 MenuInflater inflater = getMenuInflater();
1579 inflater.inflate(
R.menu.optionmenu, menu);
1581 getActionBar().setDisplayShowHomeEnabled(
true);
1582 getActionBar().setIcon(
R.drawable.ic_launcher);
1584 mItemSave = menu.findItem(
R.id.save);
1585 mItemOpen = menu.findItem(
R.id.open);
1586 mItemNewScan = menu.findItem(
R.id.new_scan);
1587 mItemPostProcessing = menu.findItem(
R.id.post_processing);
1588 mItemExport = menu.findItem(
R.id.export);
1589 mItemSettings = menu.findItem(
R.id.settings);
1590 mItemModes = menu.findItem(
R.id.modes);
1591 mItemResume = menu.findItem(
R.id.resume);
1592 mItemLocalizationMode = menu.findItem(
R.id.localization_mode);
1593 mItemTrajectoryMode = menu.findItem(
R.id.trajectory_mode);
1594 mItemRenderingPointCloud = menu.findItem(
R.id.point_cloud);
1595 mItemRenderingMesh = menu.findItem(
R.id.mesh);
1596 mItemRenderingTextureMesh = menu.findItem(
R.id.texture_mesh);
1597 mItemDataRecorderMode = menu.findItem(
R.id.data_recorder);
1598 mItemStatusVisibility = menu.findItem(
R.id.status);
1599 mItemDebugVisibility = menu.findItem(
R.id.debug);
1600 mItemSave.setEnabled(
false);
1601 mItemNewScan.setEnabled(
true);
1602 mItemExport.setEnabled(
false);
1603 mItemOpen.setEnabled(
true);
1604 mItemPostProcessing.setEnabled(
false);
1605 mItemDataRecorderMode.setEnabled(
false);
1609 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
1610 int renderingType = sharedPref.getInt(getString(
R.string.pref_key_rendering), Integer.parseInt(getString(
R.string.pref_default_rendering)));
1611 if(renderingType == 0)
1613 mItemRenderingPointCloud.setChecked(
true);
1615 else if(renderingType == 1)
1617 mItemRenderingMesh.setChecked(
true);
1621 mItemRenderingTextureMesh.setChecked(
true);
1625 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
1626 mItemRenderingTextureMesh.isChecked());
1628 if(mButtonBackfaceShown !=
null)
1630 mButtonBackfaceShown.setVisibility(mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked()?View.VISIBLE:View.INVISIBLE);
1635 Log.e(TAG,
"Error parsing rendering preferences: " +
e.getMessage());
1636 mToast.makeText(
this, String.format(
"Error parsing rendering preferences: "+
e.getMessage()), mToast.LENGTH_LONG).show();
1639 updateState(mState);
1646 MemoryInfo mi =
new MemoryInfo();
1647 ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
1648 activityManager.getMemoryInfo(mi);
1649 return mi.availMem / 0x100000
L;
1654 if(mItemStatusVisibility !=
null && mItemDebugVisibility !=
null)
1666 mRenderer.
updateTexts(Arrays.copyOfRange(mStatusTexts, 0, STATUS_TEXTS_POSE_INDEX-1));
1668 else if(mItemDebugVisibility.isChecked())
1670 mRenderer.
updateTexts(Arrays.copyOfRange(mStatusTexts, STATUS_TEXTS_POSE_INDEX-1, mStatusTexts.length));
1677 if(mGLView.getRenderMode() == GLSurfaceView.RENDERMODE_WHEN_DIRTY)
1679 mGLView.requestRender();
1688 float optimizationMaxError,
1689 float optimizationMaxErrorRatio,
1690 boolean fastMovement,
1691 int landmarkDetected,
1692 String[] statusTexts)
1694 for(
int i = 1;
i<mStatusTexts.length &&
i<statusTexts.length; ++
i)
1696 mStatusTexts[
i] = statusTexts[
i];
1700 String updateValue = mUpdateRate.compareTo(
"0")==0?
"Max":mUpdateRate;
1701 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));
1704 updateStatusTexts();
1708 if(mButtonStart.getVisibility() != View.VISIBLE)
1711 long memoryFree = getFreeMemory();
1712 long memoryUsed = mFreeMemoryOnStart>memoryFree?mFreeMemoryOnStart-memoryFree:0;
1714 if(memoryFree < 400)
1718 if(mMemoryWarningDialog!=
null)
1720 mMemoryWarningDialog.dismiss();
1721 mMemoryWarningDialog =
null;
1724 mMemoryWarningDialog =
new AlertDialog.Builder(getActivity())
1725 .setTitle(
"Memory is full!")
1726 .setCancelable(
false)
1727 .setMessage(String.format(
"Scanning has been paused because free memory is too "
1728 +
"low (%d MB). You should be able to save the database but some post-processing and exporting options may fail. "
1729 +
"\n\nNote that for large environments, you can save multiple databases and "
1730 +
"merge them with RTAB-Map Desktop version.", memoryUsed))
1731 .setPositiveButton(
"Ok",
new DialogInterface.OnClickListener() {
1732 public void onClick(DialogInterface dialog, int which) {
1733 mMemoryWarningDialog = null;
1736 .setNeutralButton(
"Save",
new DialogInterface.OnClickListener() {
1737 public void onClick(DialogInterface dialog, int which) {
1739 mMemoryWarningDialog = null;
1743 mMemoryWarningDialog.setCanceledOnTouchOutside(
false);
1744 mMemoryWarningDialog.show();
1746 else if(mMemoryWarningDialog ==
null && memoryUsed*3 > memoryFree && (mItemDataRecorderMode ==
null || !mItemDataRecorderMode.isChecked()))
1748 mMemoryWarningDialog =
new AlertDialog.Builder(getActivity())
1749 .setTitle(
"Warning: Memory is almost full!")
1750 .setCancelable(
false)
1751 .setMessage(String.format(
"Free memory (%d MB) should be at least 3 times the "
1752 +
"memory used (%d MB) so that some post-processing and exporting options "
1753 +
"have enough memory to work correctly. If you just want to save the database "
1754 +
"after scanning, you can continue until the next warning.\n\n"
1755 +
"Note that showing only point clouds reduces memory needed for rendering.", memoryFree, memoryUsed))
1756 .setPositiveButton(
"Pause",
new DialogInterface.OnClickListener() {
1757 public void onClick(DialogInterface dialog, int which) {
1761 .setNeutralButton(
"Continue",
new DialogInterface.OnClickListener() {
1762 public void onClick(DialogInterface dialog, int which) {
1766 mMemoryWarningDialog.setCanceledOnTouchOutside(
false);
1767 mMemoryWarningDialog.show();
1773 if(mState ==
State.STATE_MAPPING || mState ==
State.STATE_VISUALIZING_CAMERA)
1775 long currentTime = System.currentTimeMillis()/1000;
1776 if(loopClosureId > 0)
1778 mToast.setText(String.format(
"Loop closure detected! (%d/%d inliers)", inliers, matches));
1781 else if(landmarkDetected != 0)
1783 mToast.setText(String.format(
"Marker %d detected!", landmarkDetected));
1786 else if(rejected > 0)
1788 if(inliers >= Integer.parseInt(mMinInliers))
1790 if(optimizationMaxError > 0.0f)
1792 mToast.setText(String.format(
"Loop closure rejected, too high graph optimization error (%.3fm: ratio=%.3f < factor=%sx).", optimizationMaxError, optimizationMaxErrorRatio, mMaxOptimizationError));
1796 mToast.setText(String.format(
"Loop closure rejected, graph optimization failed! You may try a different Graph Optimizer (see Mapping options)."));
1801 mToast.setText(String.format(
"Loop closure rejected, not enough inliers (%d/%d < %s).", inliers, matches, mMinInliers));
1805 else if(fastMovement)
1807 if(currentTime - mLastFastMovementNotificationStamp > 3)
1809 mToast.setText(
"Move slower... blurry images are not added to map (\"Settings->Mapping...->Maximum Motion Speed\" is enabled).");
1816 mLastFastMovementNotificationStamp = currentTime;
1827 final float updateTime,
1828 final int loopClosureId,
1829 final int highestHypId,
1830 final int databaseMemoryUsed,
1833 final int featuresExtracted,
1834 final float hypothesis,
1835 final int nodesDrawn,
1838 final float rehearsalValue,
1839 final float optimizationMaxError,
1840 final float optimizationMaxErrorRatio,
1841 final float distanceTravelled,
1842 final int fastMovement,
1843 final int landmarkDetected,
1851 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateStatsCallback()"));
1853 final String[] statusTexts =
new String[STATUS_TEXTS_SIZE];
1855 long memoryFree = getFreeMemory();
1856 statusTexts[1] = getString(
R.string.memory)+(mFreeMemoryOnStart>memoryFree?mFreeMemoryOnStart-memoryFree:0);
1857 statusTexts[2] = getString(
R.string.free_memory)+memoryFree;
1859 if(loopClosureId > 0)
1861 ++mTotalLoopClosures;
1868 if(mLastKnownLocation !=
null)
1870 long millisec = System.currentTimeMillis() - mLastKnownLocation.getTime();
1873 statusTexts[3] = getString(
R.string.gps)+String.format(
"[too old, %d ms]", millisec);
1877 statusTexts[3] = getString(
R.string.gps)+
1878 String.format(
"%.2f %.2f %.2fm %.0fdeg %.0fm",
1879 mLastKnownLocation.getLongitude(),
1880 mLastKnownLocation.getLatitude(),
1881 mLastKnownLocation.getAltitude(),
1883 mLastKnownLocation.getAccuracy());
1888 statusTexts[3] = getString(
R.string.gps)+String.format(
"[not yet available, %.0fdeg]", mCompassDeg);
1891 if(mEnvSensorsSaved)
1893 statusTexts[4] = getString(
R.string.env_sensors);
1895 if(mLastEnvSensorsSet[0])
1897 statusTexts[4] += String.format(
" %.0f dbm", mLastEnvSensors[0]);
1898 mLastEnvSensorsSet[0] =
false;
1900 if(mLastEnvSensorsSet[1])
1902 statusTexts[4] += String.format(
" %.1f %cC", mLastEnvSensors[1],
'\u00B0');
1903 mLastEnvSensorsSet[1] =
false;
1905 if(mLastEnvSensorsSet[2])
1907 statusTexts[4] += String.format(
" %.1f hPa", mLastEnvSensors[2]);
1908 mLastEnvSensorsSet[2] =
false;
1910 if(mLastEnvSensorsSet[3])
1912 statusTexts[4] += String.format(
" %.0f lx", mLastEnvSensors[3]);
1913 mLastEnvSensorsSet[3] =
false;
1915 if(mLastEnvSensorsSet[4])
1917 statusTexts[4] += String.format(
" %.0f %%", mLastEnvSensors[4]);
1918 mLastEnvSensorsSet[4] =
false;
1922 String formattedDate =
new SimpleDateFormat(
"HH:mm:ss.SSS").format(
new Date());
1923 statusTexts[5] = getString(
R.string.time)+formattedDate;
1925 int index = STATUS_TEXTS_POSE_INDEX;
1926 statusTexts[index++] = getString(
R.string.nodes)+
nodes+
" (" + nodesDrawn +
" shown)";
1927 statusTexts[index++] = getString(
R.string.words)+words;
1928 statusTexts[index++] = getString(
R.string.database_size)+databaseMemoryUsed;
1929 statusTexts[index++] = getString(
R.string.points)+points;
1930 statusTexts[index++] = getString(
R.string.polygons)+polygons;
1931 statusTexts[index++] = getString(
R.string.update_time)+(
int)(updateTime) +
" / " + (mTimeThr.compareTo(
"0")==0?
"No Limit":mTimeThr);
1932 statusTexts[index++] = getString(
R.string.features)+featuresExtracted +
" / " + (mMaxFeatures.compareTo(
"0")==0?
"No Limit":mMaxFeatures.compareTo(
"-1")==0?
"Disabled":mMaxFeatures);
1933 statusTexts[index++] = getString(
R.string.rehearsal)+(
int)(rehearsalValue*100.0
f);
1934 statusTexts[index++] = getString(
R.string.total_loop)+mTotalLoopClosures;
1935 statusTexts[index++] = getString(
R.string.inliers)+inliers;
1936 statusTexts[index++] = getString(
R.string.hypothesis)+(
int)(hypothesis*100.0
f) +
" / " + (
int)(
Float.parseFloat(mLoopThr)*100.0f) +
" (" + (loopClosureId>0?loopClosureId:highestHypId)+
")";
1937 statusTexts[index++] = getString(
R.string.fps)+(
int)fps+
" Hz";
1938 statusTexts[index++] = getString(
R.string.distance)+(
int)distanceTravelled+
" m";
1939 statusTexts[index++] = String.format(
"Pose (x,y,z): %.2f %.2f %.2f",
x,
y,
z);
1941 runOnUiThread(
new Runnable() {
1943 updateStatsUI(loopClosureId, inliers,
matches, rejected, optimizationMaxError, optimizationMaxErrorRatio, fastMovement!=0, landmarkDetected, statusTexts);
1952 if(!DISABLE_LOG) Log.i(TAG, String.format(
"rtabmapInitEventsUI() status=%d msg=%s", status,
msg));
1954 int optimizedMeshDetected = 0;
1956 if(
msg.equals(
"Loading optimized cloud...done!"))
1958 optimizedMeshDetected = 1;
1960 else if(
msg.equals(
"Loading optimized mesh...done!"))
1962 optimizedMeshDetected = 2;
1964 else if(
msg.equals(
"Loading optimized texture mesh...done!"))
1966 optimizedMeshDetected = 3;
1968 if(optimizedMeshDetected > 0)
1970 resetNoTouchTimer();
1971 mSavedRenderingType = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2;
1972 if(optimizedMeshDetected==1)
1974 mItemRenderingPointCloud.setChecked(
true);
1976 else if(optimizedMeshDetected==2)
1978 mItemRenderingMesh.setChecked(
true);
1982 mItemRenderingTextureMesh.setChecked(
true);
1986 if(mButtonCameraView.getSelectedItemPosition() == 0)
1990 mToast.makeText(getActivity(), String.format(
"Optimized mesh detected in the database, it is shown while the database is loading..."), mToast.LENGTH_LONG).show();
1991 mProgressDialog.dismiss();
1994 if(mButtonStart!=
null)
1996 mStatusTexts[0] = getString(
R.string.status)+(status == 1 &&
msg.isEmpty()?mState ==
State.
STATE_CAMERA?
"Camera Preview":
"Idle":
msg);
1998 long freeMemory = getFreeMemory();
1999 mStatusTexts[1] = getString(
R.string.memory)+String.valueOf(mFreeMemoryOnStart>freeMemory?mFreeMemoryOnStart-freeMemory:0);
2000 mStatusTexts[2] = getString(
R.string.free_memory)+String.valueOf(freeMemory);
2001 updateStatusTexts();
2010 if(!DISABLE_LOG) Log.i(TAG, String.format(
"rtabmapInitEventCallback()"));
2012 runOnUiThread(
new Runnable() {
2014 rtabmapInitEventUI(status,
msg);
2023 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateProgressionUI() count=%d max=%s",
count,
max));
2025 mExportProgressDialog.setMax(
max);
2026 mExportProgressDialog.setProgress(
count);
2034 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateProgressionCallback()"));
2036 runOnUiThread(
new Runnable() {
2062 else if(
key.
equals(
"FisheyeOverExposed"))
2064 else if(
key.
equals(
"FisheyeUnderExposed"))
2068 else if(
key.
equals(
"ColorUnderExposed"))
2072 else if(
key.
equals(
"TooFewFeaturesTracked"))
2074 if(!
value.equals(
"0"))
2076 str = String.
format(
"Too few features (%s) were tracked in the fisheye image. This may result in poor odometry!",
value);
2083 str = String.
format(
"Too close! Tip: Scan from at least ~1 meter from surfaces.",
value);
2086 else if(
key.
equals(
"TangoPoseEventNotReceived"))
2088 str = String.
format(
"No valid tango pose event received since %s sec.",
value);
2092 str = String.
format(
"Unknown Camera event detected!? (type=%d, key=%s, value=%s)",
type,
key,
value);
2096 mToast.setText(
str);
2107 runOnUiThread(
new Runnable() {
2115 int versionNumber = 0;
2116 String packageName = TANGO_PACKAGE_NAME;
2118 PackageInfo
pi = getApplicationContext().getPackageManager().getPackageInfo(packageName,
2119 PackageManager.GET_META_DATA);
2120 versionNumber =
pi.versionCode;
2121 }
catch (NameNotFoundException
e) {
2122 e.printStackTrace();
2124 return (minVersion <= versionNumber);
2131 mExportProgressDialog.setTitle(
"Post-Processing");
2132 mExportProgressDialog.setMessage(String.format(
"Please wait while optimizing..."));
2133 mExportProgressDialog.setProgress(0);
2134 mExportProgressDialog.show();
2137 Thread workingThread =
new Thread(
new Runnable() {
2140 runOnUiThread(
new Runnable() {
2143 if(mExportProgressDialog.isShowing())
2145 mExportProgressDialog.dismiss();
2146 if(loopDetected >= 0)
2148 mTotalLoopClosures+=loopDetected;
2149 if(withStandardMeshExport)
2151 export(
true,
true,
false,
true, 200000);
2155 mProgressDialog.setTitle(
"Post-Processing");
2156 mProgressDialog.setMessage(String.format(
"Optimization done! Increasing visual appeal..."));
2157 mProgressDialog.show();
2159 if(mOpenedDatabasePath.isEmpty())
2165 else if(loopDetected < 0)
2167 mToast.makeText(getActivity(), String.format(
"Optimization failed!"), mToast.LENGTH_LONG).show();
2172 mProgressDialog.dismiss();
2173 mToast.makeText(getActivity(), String.format(
"Optimization canceled"), mToast.LENGTH_LONG).show();
2179 workingThread.start();
2182 private Handler notouchHandler =
new Handler(){
2183 public void handleMessage(Message
msg) {
2187 private Runnable notouchCallback =
new Runnable() {
2190 if(!mProgressDialog.isShowing() && !mMenuOpened)
2192 setNavVisibility(
false);
2193 mHudVisible =
false;
2194 updateState(mState);
2198 resetNoTouchTimer();
2204 resetNoTouchTimer(
false);
2211 setNavVisibility(
true);
2212 if(mItemSave !=
null)
2214 updateState(mState);
2218 notouchHandler.removeCallbacks(notouchCallback);
2219 notouchHandler.postDelayed(notouchCallback, NOTOUCH_TIMEOUT);
2221 if(mGLView.getRenderMode() == GLSurfaceView.RENDERMODE_WHEN_DIRTY)
2223 mGLView.requestRender();
2228 notouchHandler.removeCallbacks(notouchCallback);
2229 Timer
timer =
new Timer();
2237 mToast.makeText(getActivity(), String.format(
"Re-adding %d online clouds, this may take some time...", mMapNodes), mToast.LENGTH_LONG).show();
2240 if(!DISABLE_LOG) Log.i(TAG, String.format(
"updateState() state=%s hud=%d",
state.toString(), mHudVisible?1:0));
2241 mStatusTexts[0] =
state.toString();
2246 mButtonLighting.setVisibility(View.INVISIBLE);
2247 mButtonWireframe.setVisibility(View.INVISIBLE);
2248 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
2249 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2250 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2251 mButtonLibrary.setVisibility(View.INVISIBLE);
2252 mButtonNewScan.setVisibility(View.INVISIBLE);
2253 mItemSave.setEnabled(
false);
2254 mItemExport.setEnabled(
false);
2255 mItemOpen.setEnabled(
false);
2256 mItemNewScan.setEnabled(
true);
2257 mItemPostProcessing.setEnabled(
false);
2258 mItemSettings.setEnabled(
false);
2259 mItemResume.setEnabled(
false);
2261 mItemLocalizationMode.setEnabled(
true);
2262 mItemTrajectoryMode.setEnabled(
true);
2263 mItemDataRecorderMode.setEnabled(
true);
2264 mButtonStart.setVisibility(mState ==
State.
STATE_CAMERA?View.VISIBLE:View.INVISIBLE);
2265 mButtonStop.setVisibility(mHudVisible && mState ==
State.
STATE_MAPPING?View.VISIBLE:View.INVISIBLE);
2267 case STATE_PROCESSING:
2268 mButtonLighting.setVisibility(View.INVISIBLE);
2269 mButtonWireframe.setVisibility(View.INVISIBLE);
2270 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
2271 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2272 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2273 mButtonLibrary.setVisibility(View.INVISIBLE);
2274 mButtonNewScan.setVisibility(View.INVISIBLE);
2275 mItemSave.setEnabled(
false);
2276 mItemExport.setEnabled(
false);
2277 mItemOpen.setEnabled(
false);
2278 mItemNewScan.setEnabled(
false);
2279 mItemPostProcessing.setEnabled(
false);
2280 mItemSettings.setEnabled(
false);
2281 mItemResume.setEnabled(
false);
2282 mItemModes.setEnabled(
false);
2283 mButtonStart.setVisibility(View.INVISIBLE);
2284 mButtonStop.setVisibility(View.INVISIBLE);
2286 case STATE_VISUALIZING:
2287 case STATE_VISUALIZING_CAMERA:
2288 mButtonLighting.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2289 mButtonWireframe.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2291 mButtonCloseVisualization.setEnabled(
true);
2294 mButtonLibrary.setVisibility(View.INVISIBLE);
2295 mButtonNewScan.setVisibility(View.INVISIBLE);
2300 mItemPostProcessing.setEnabled(
false);
2304 mItemLocalizationMode.setEnabled(
true);
2305 mItemTrajectoryMode.setEnabled(
false);
2306 mItemDataRecorderMode.setEnabled(
false);
2307 mButtonStart.setVisibility(View.INVISIBLE);
2310 case STATE_VISUALIZING_WHILE_LOADING:
2311 mButtonLighting.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2312 mButtonWireframe.setVisibility(mHudVisible && !mItemRenderingPointCloud.isChecked()?View.VISIBLE:View.INVISIBLE);
2313 mButtonCloseVisualization.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE);
2314 mButtonCloseVisualization.setEnabled(
false);
2315 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2316 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2317 mButtonLibrary.setVisibility(View.INVISIBLE);
2318 mButtonNewScan.setVisibility(View.INVISIBLE);
2319 mItemSave.setEnabled(
false);
2320 mItemExport.setEnabled(
false);
2321 mItemOpen.setEnabled(
false);
2322 mItemPostProcessing.setEnabled(
false);
2323 mItemSettings.setEnabled(
false);
2324 mItemResume.setEnabled(
false);
2325 mItemModes.setEnabled(
false);
2326 mButtonStart.setVisibility(View.INVISIBLE);
2327 mButtonStop.setVisibility(View.INVISIBLE);
2330 mButtonLighting.setVisibility(View.INVISIBLE);
2331 mButtonWireframe.setVisibility(View.INVISIBLE);
2332 mButtonCloseVisualization.setVisibility(View.INVISIBLE);
2333 mButtonSaveOnDevice.setVisibility(View.INVISIBLE);
2334 mButtonShareOnSketchfab.setVisibility(View.INVISIBLE);
2335 mButtonLibrary.setVisibility(mState==
State.
STATE_WELCOME?View.VISIBLE:View.INVISIBLE);
2336 mButtonNewScan.setVisibility(mState==
State.
STATE_WELCOME?View.VISIBLE:View.INVISIBLE);
2337 mItemSave.setEnabled(mMapNodes>0);
2338 mItemExport.setEnabled(mMapNodes>0);
2339 mItemOpen.setEnabled(
true);
2340 mItemNewScan.setEnabled(
true);
2341 mItemPostProcessing.setEnabled(mMapNodes>0);
2342 mItemSettings.setEnabled(
true);
2343 mItemResume.setEnabled(mMapNodes>0);
2344 mItemModes.setEnabled(
true);
2345 mButtonStart.setVisibility(View.INVISIBLE);
2346 mButtonStop.setVisibility(View.INVISIBLE);
2347 mItemLocalizationMode.setEnabled(
true);
2348 mItemDataRecorderMode.setEnabled(
true);
2349 mItemTrajectoryMode.setEnabled(
true);
2352 mButtonCameraView.setVisibility(mHudVisible?View.VISIBLE:View.INVISIBLE);
2353 mButtonBackfaceShown.setVisibility(mHudVisible && (mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked())?View.VISIBLE:View.INVISIBLE);
2354 mSeekBarOrthoCut.setVisibility(mHudVisible && mButtonCameraView.getSelectedItemPosition() == 3?View.VISIBLE:View.INVISIBLE);
2355 mSeekBarGrid.setVisibility(mHudVisible && mSeekBarGrid.isEnabled() && mButtonCameraView.getSelectedItemPosition() == 3?View.VISIBLE:View.INVISIBLE);
2359 mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
2360 mGLView.requestRender();
2364 mGLView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
2370 mIntentDbToOpen =
null;
2375 if(!DISABLE_LOG) Log.i(TAG, String.format(
"startMapping()"));
2379 if(mMemoryWarningDialog !=
null)
2381 mMemoryWarningDialog.dismiss();
2382 mMemoryWarningDialog=
null;
2385 mLastFastMovementNotificationStamp = System.currentTimeMillis()/1000;
2387 if(mItemDataRecorderMode.isChecked())
2389 mToast.makeText(getActivity(), String.format(
"Data Recorder Mode: no map is created, only raw data is recorded."), mToast.LENGTH_LONG).show();
2391 else if(mMapNodes>0)
2393 if(mItemLocalizationMode!=
null && mItemLocalizationMode.isChecked())
2395 mToast.makeText(getActivity(), String.format(
"Localization mode"), mToast.LENGTH_LONG).show();
2399 mToast.makeText(getActivity(), String.format(
"On resume, a new map is created. Tip: Try relocalizing in the previous area."), mToast.LENGTH_LONG).show();
2402 else if(mMapNodes==0 && mItemLocalizationMode!=
null && mItemLocalizationMode.isChecked())
2404 mItemLocalizationMode.setChecked(
false);
2406 mToast.makeText(getActivity(), String.format(
"Disabled localization mode as the map is empty, now mapping..."), mToast.LENGTH_LONG).show();
2412 mProgressDialog.setTitle(
"");
2413 mProgressDialog.setMessage(
"Stopping camera...");
2414 mProgressDialog.show();
2433 if(mArCoreCamera !=
null)
2435 synchronized (
this) {
2437 mArCoreCamera.
close();
2438 mArCoreCamera =
null;
2442 Thread stopThread =
new Thread(
new Runnable() {
2444 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopCamera()"));
2446 if(mCameraServiceConnectionUsed)
2448 if(!DISABLE_LOG) Log.i(TAG, String.format(
"unbindService"));
2449 getActivity().unbindService(mCameraServiceConnection);
2451 mCameraServiceConnectionUsed =
false;
2453 runOnUiThread(
new Runnable() {
2456 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopMapping(): runOnUiThread"));
2457 mProgressDialog.dismiss();
2467 mProgressDialog.setTitle(
"");
2468 mProgressDialog.setMessage(
"Stopping camera...");
2469 mProgressDialog.show();
2473 if(mArCoreCamera !=
null)
2475 synchronized (
this) {
2477 mArCoreCamera.
close();
2478 mArCoreCamera =
null;
2482 Thread stopThread =
new Thread(
new Runnable() {
2484 if(!DISABLE_LOG) Log.i(TAG, String.format(
"setPausedMapping()"));
2486 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopCamera()"));
2488 if(mCameraServiceConnectionUsed)
2490 if(!DISABLE_LOG) Log.i(TAG, String.format(
"unbindService"));
2491 getActivity().unbindService(mCameraServiceConnection);
2493 mCameraServiceConnectionUsed =
false;
2495 runOnUiThread(
new Runnable() {
2497 if(!DISABLE_LOG) Log.i(TAG, String.format(
"stopMapping(): runOnUiThread"));
2498 mProgressDialog.dismiss();
2502 long freeMemory = getFreeMemory();
2503 mStatusTexts[1] = getString(
R.string.memory)+String.valueOf(mFreeMemoryOnStart>freeMemory?mFreeMemoryOnStart-freeMemory:0);
2504 mStatusTexts[2] = getString(
R.string.free_memory)+String.valueOf(freeMemory);
2505 updateStatusTexts();
2507 mDateOnPause =
new Date();
2509 long memoryFree = getFreeMemory();
2510 if(!mOnPause && !mItemLocalizationMode.isChecked() && !mItemDataRecorderMode.isChecked() && memoryFree >= 100 && mMapNodes>2)
2512 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Do standard processing>?"));
2514 AlertDialog
d2 =
new AlertDialog.Builder(getActivity())
2515 .setCancelable(
false)
2516 .setTitle(
"Mapping Stopped! Optimize Now?")
2517 .setMessage(
"Do you want to do standard graph and mesh optimizations now? This can be also done later using \"Optimize\" and \"Export\" menus.")
2518 .setNeutralButton(
"Only Graph",
new DialogInterface.OnClickListener() {
2519 public void onClick(DialogInterface dialog, int which) {
2520 standardOptimization(false);
2523 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
2524 public void onClick(DialogInterface dialog, int which) {
2525 standardOptimization(true);
2528 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
2529 public void onClick(DialogInterface dialog, int which) {
2530 if(mOpenedDatabasePath.isEmpty())
2537 d2.setCanceledOnTouchOutside(
false);
2548 resetNoTouchTimer();
2549 if(!DISABLE_LOG) Log.i(TAG,
"called onOptionsItemSelected; selected item: " + item);
2550 int itemId = item.getItemId();
2551 if (itemId ==
R.id.post_processing_standard)
2553 standardOptimization(
false);
2555 else if (itemId ==
R.id.detect_more_loop_closures)
2557 mProgressDialog.setTitle(
"Post-Processing");
2558 mProgressDialog.setMessage(String.format(
"Please wait while detecting more loop closures..."));
2559 mProgressDialog.show();
2561 Thread workingThread =
new Thread(
new Runnable() {
2564 runOnUiThread(
new Runnable() {
2566 mProgressDialog.dismiss();
2567 if(loopDetected >= 0)
2569 mTotalLoopClosures+=loopDetected;
2570 mToast.makeText(getActivity(), String.format(
"Detection done! %d new loop closure(s) added.", loopDetected), mToast.LENGTH_SHORT).show();
2572 else if(loopDetected < 0)
2574 mToast.makeText(getActivity(), String.format(
"Detection failed!"), mToast.LENGTH_SHORT).show();
2581 workingThread.start();
2583 else if (itemId ==
R.id.global_graph_optimization)
2585 mProgressDialog.setTitle(
"Post-Processing");
2586 mProgressDialog.setMessage(String.format(
"Global graph optimization..."));
2587 mProgressDialog.show();
2589 Thread workingThread =
new Thread(
new Runnable() {
2592 runOnUiThread(
new Runnable() {
2594 mProgressDialog.dismiss();
2597 mToast.makeText(getActivity(), String.format(
"Optimization done!"), mToast.LENGTH_SHORT).show();
2601 mToast.makeText(getActivity(), String.format(
"Optimization failed!"), mToast.LENGTH_SHORT).show();
2608 workingThread.start();
2610 else if (itemId ==
R.id.polygons_filtering)
2612 mProgressDialog.setTitle(
"Post-Processing");
2613 mProgressDialog.setMessage(String.format(
"Noise filtering..."));
2614 mProgressDialog.show();
2617 else if (itemId ==
R.id.gain_compensation_fast)
2619 mProgressDialog.setTitle(
"Post-Processing");
2620 mProgressDialog.setMessage(String.format(
"Adjusting Colors (Fast)..."));
2621 mProgressDialog.show();
2624 else if (itemId ==
R.id.gain_compensation_full)
2626 mProgressDialog.setTitle(
"Post-Processing");
2627 mProgressDialog.setMessage(String.format(
"Adjusting Colors (Full)..."));
2628 mProgressDialog.show();
2631 else if (itemId ==
R.id.bilateral_filtering)
2633 mProgressDialog.setTitle(
"Post-Processing");
2634 mProgressDialog.setMessage(String.format(
"Mesh smoothing..."));
2635 mProgressDialog.show();
2638 else if (itemId ==
R.id.sba)
2640 mProgressDialog.setTitle(
"Post-Processing");
2641 mProgressDialog.setMessage(String.format(
"Bundle adjustement..."));
2642 mProgressDialog.show();
2644 Thread workingThread =
new Thread(
new Runnable() {
2647 runOnUiThread(
new Runnable() {
2649 mProgressDialog.dismiss();
2652 mToast.makeText(getActivity(), String.format(
"Optimization done!"), mToast.LENGTH_SHORT).show();
2656 mToast.makeText(getActivity(), String.format(
"Optimization failed!"), mToast.LENGTH_SHORT).show();
2662 workingThread.start();
2664 else if(itemId ==
R.id.status)
2666 item.setChecked(!item.isChecked());
2667 updateStatusTexts();
2669 else if(itemId ==
R.id.debug)
2671 item.setChecked(!item.isChecked());
2672 updateStatusTexts();
2674 else if(itemId ==
R.id.mesh || itemId ==
R.id.texture_mesh || itemId ==
R.id.point_cloud)
2676 item.setChecked(
true);
2679 mItemRenderingMesh.isChecked() || mItemRenderingTextureMesh.isChecked(),
2680 mItemRenderingTextureMesh.isChecked());
2682 resetNoTouchTimer();
2687 int type = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2;
2688 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
2689 SharedPreferences.Editor editor = sharedPref.edit();
2690 editor.putInt(getString(
R.string.pref_key_rendering),
type);
2695 else if(itemId ==
R.id.map_shown)
2697 item.setChecked(!item.isChecked());
2700 else if(itemId ==
R.id.odom_shown)
2702 item.setChecked(!item.isChecked());
2705 else if(itemId ==
R.id.localization_mode)
2707 item.setChecked(!item.isChecked());
2710 else if(itemId ==
R.id.trajectory_mode)
2712 item.setChecked(!item.isChecked());
2714 setCamera(item.isChecked()?2:1);
2716 else if(itemId ==
R.id.graph_optimization)
2718 item.setChecked(!item.isChecked());
2721 else if(itemId ==
R.id.graph_visible)
2723 item.setChecked(!item.isChecked());
2726 else if(itemId ==
R.id.grid_visible)
2728 item.setChecked(!item.isChecked());
2729 mSeekBarGrid.setEnabled(item.isChecked());
2730 mSeekBarGrid.setVisibility(mHudVisible && mSeekBarGrid.isEnabled()&&mButtonCameraView.getSelectedItemPosition() == 3?View.VISIBLE:View.INVISIBLE);
2733 else if (itemId ==
R.id.save)
2737 else if(itemId ==
R.id.resume)
2741 else if(itemId ==
R.id.new_scan)
2745 else if(itemId ==
R.id.data_recorder)
2747 final boolean dataRecorderOldState = item.isChecked();
2748 AlertDialog
d2 =
new AlertDialog.Builder(getActivity())
2749 .setCancelable(
false)
2750 .setTitle(
"Data Recorder Mode")
2751 .setMessage(
"Changing from/to data recorder mode will close the current session. Do you want to continue?")
2752 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
2753 public void onClick(DialogInterface dialog, int which) {
2755 mTotalLoopClosures = 0;
2756 int index = STATUS_TEXTS_POSE_INDEX;
2758 mStatusTexts[index++] = getString(R.string.nodes)+0;
2759 mStatusTexts[index++] = getString(R.string.words)+0;
2760 mStatusTexts[index++] = getString(R.string.database_size)+0;
2761 mStatusTexts[index++] = getString(R.string.points)+0;
2762 mStatusTexts[index++] = getString(R.string.polygons)+0;
2763 mStatusTexts[index++] = getString(R.string.update_time)+0;
2764 mStatusTexts[index++] = getString(R.string.features)+0;
2765 mStatusTexts[index++] = getString(R.string.rehearsal)+0;
2766 mStatusTexts[index++] = getString(R.string.total_loop)+0;
2767 mStatusTexts[index++] = getString(R.string.inliers)+0;
2768 mStatusTexts[index++] = getString(R.string.hypothesis)+0;
2769 mStatusTexts[index++] = getString(R.string.fps)+0;
2770 mStatusTexts[index++] = getString(R.string.distance)+0;
2771 mStatusTexts[index++] = String.format(
"Pose (x,y,z): 0 0 0");
2772 updateStatusTexts();
2774 mItemDataRecorderMode.setChecked(!dataRecorderOldState);
2775 RTABMapLib.setDataRecorderMode(nativeApplication, mItemDataRecorderMode.isChecked());
2777 mOpenedDatabasePath =
"";
2778 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
2779 boolean databaseInMemory = sharedPref.getBoolean(getString(R.string.pref_key_db_in_memory), Boolean.parseBoolean(getString(R.string.pref_default_db_in_memory)));
2780 String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB;
2781 RTABMapLib.openDatabase(nativeApplication, tmpDatabase, databaseInMemory, false, true);
2783 mItemLocalizationMode.setEnabled(!mItemDataRecorderMode.isChecked());
2785 if(mItemDataRecorderMode.isChecked())
2787 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();
2791 mToast.makeText(getActivity(), String.format(
"Data recorder mode deactivated!"), mToast.LENGTH_LONG).show();
2795 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
2796 public void onClick(DialogInterface dialog, int which) {
2801 d2.setCanceledOnTouchOutside(
false);
2804 else if(itemId ==
R.id.export_point_cloud ||
2805 itemId ==
R.id.export_point_cloud_highrez)
2807 final boolean regenerateCloud = itemId ==
R.id.export_point_cloud_highrez;
2809 export(
false,
false, regenerateCloud,
false, 0);
2811 else if(itemId ==
R.id.export_optimized_mesh ||
2812 itemId ==
R.id.export_optimized_mesh_texture)
2814 final boolean isOBJ = itemId ==
R.id.export_optimized_mesh_texture;
2816 RelativeLayout linearLayout =
new RelativeLayout(
this);
2817 final NumberPicker aNumberPicker =
new NumberPicker(
this);
2818 aNumberPicker.setMaxValue(9);
2819 aNumberPicker.setMinValue(0);
2820 aNumberPicker.setWrapSelectorWheel(
false);
2821 aNumberPicker.setDescendantFocusability(NumberPicker.FOCUS_BLOCK_DESCENDANTS);
2822 aNumberPicker.setFormatter(
new NumberPicker.Formatter() {
2824 public String format(int i) {
2829 return String.format(
"%d00 000", i);
2832 aNumberPicker.setValue(2);
2836 Method method = aNumberPicker.getClass().getDeclaredMethod(
"changeValueByOne",
boolean.
class);
2837 method.setAccessible(
true);
2838 method.invoke(aNumberPicker,
true);
2839 }
catch (NoSuchMethodException
e) {
2840 e.printStackTrace();
2841 }
catch (IllegalArgumentException
e) {
2842 e.printStackTrace();
2843 }
catch (IllegalAccessException
e) {
2844 e.printStackTrace();
2845 }
catch (InvocationTargetException
e) {
2846 e.printStackTrace();
2850 RelativeLayout.LayoutParams
params =
new RelativeLayout.LayoutParams(50, 50);
2851 RelativeLayout.LayoutParams numPicerParams =
new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
2852 numPicerParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
2854 linearLayout.setLayoutParams(params);
2855 linearLayout.addView(aNumberPicker,numPicerParams);
2857 AlertDialog ad =
new AlertDialog.Builder(
this)
2858 .setTitle(
"Maximum polygons")
2859 .setView(linearLayout)
2860 .setCancelable(
false)
2861 .setPositiveButton(
"Ok",
2862 new DialogInterface.OnClickListener() {
2863 public void onClick(DialogInterface dialog,
2865 export(isOBJ, true, false, true, aNumberPicker.getValue()*100000);
2868 .setNegativeButton(
"Cancel",
2869 new DialogInterface.OnClickListener() {
2870 public void onClick(DialogInterface dialog,
2875 ad.setCanceledOnTouchOutside(
false);
2878 else if(itemId ==
R.id.open)
2882 else if(itemId ==
R.id.settings)
2884 Intent intent =
new Intent(getActivity(), SettingsActivity.class);
2885 startActivity(intent);
2887 else if(itemId ==
R.id.about)
2889 AboutDialog about =
new AboutDialog(
this);
2890 about.setTitle(
"About RTAB-Map");
2900 startCamera(String.format(
"Hold Tight! Initializing Camera Service...\n"
2901 +
"Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
2909 closeVisualization();
2912 mTotalLoopClosures = 0;
2914 int index = STATUS_TEXTS_POSE_INDEX;
2916 mStatusTexts[index++] = getString(
R.string.nodes)+0;
2917 mStatusTexts[index++] = getString(
R.string.words)+0;
2918 mStatusTexts[index++] = getString(
R.string.database_size)+0;
2919 mStatusTexts[index++] = getString(
R.string.points)+0;
2920 mStatusTexts[index++] = getString(
R.string.polygons)+0;
2921 mStatusTexts[index++] = getString(
R.string.update_time)+0;
2922 mStatusTexts[index++] = getString(
R.string.features)+0;
2923 mStatusTexts[index++] = getString(
R.string.rehearsal)+0;
2924 mStatusTexts[index++] = getString(
R.string.total_loop)+0;
2925 mStatusTexts[index++] = getString(
R.string.inliers)+0;
2926 mStatusTexts[index++] = getString(
R.string.hypothesis)+0;
2927 mStatusTexts[index++] = getString(
R.string.fps)+0;
2928 mStatusTexts[index++] = getString(
R.string.distance)+0;
2929 mStatusTexts[index++] = String.format(
"Pose (x,y,z): 0 0 0");
2930 updateStatusTexts();
2932 mOpenedDatabasePath =
"";
2933 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
2934 boolean databaseInMemory = sharedPref.getBoolean(getString(
R.string.pref_key_db_in_memory),
Boolean.parseBoolean(getString(
R.string.pref_default_db_in_memory)));
2935 final String tmpDatabase = mWorkingDirectory+RTABMAP_TMP_DB;
2937 File newFile =
new File(tmpDatabase);
2938 final int fileSizeMB = (
int)newFile.length()/(1024 * 1024);
2943 AlertDialog
d2 =
new AlertDialog.Builder(getActivity())
2944 .setCancelable(
false)
2945 .setTitle(
"Recovery")
2946 .setMessage(String.format(
"The previous session (%d MB) was not correctly saved, do you want to recover it?", fileSizeMB))
2947 .setNegativeButton(
"Ignore",
new DialogInterface.OnClickListener() {
2948 public void onClick(DialogInterface dialog,
int which) {
2949 (
new File(tmpDatabase)).
delete();
2953 .setNeutralButton(
"Cancel",
new DialogInterface.OnClickListener() {
2954 public void onClick(DialogInterface dialog,
int which) {
2958 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
2959 public void onClick(DialogInterface dialog,
int which) {
2960 final String fileName =
new SimpleDateFormat(
"yyMMdd-HHmmss").format(
new Date()) +
".db";
2961 final String outputDbPath = mWorkingDirectory + fileName;
2963 mExportProgressDialog.setTitle(
"Recovering");
2964 mExportProgressDialog.setMessage(String.format(
"Please wait while recovering data..."));
2965 mExportProgressDialog.setProgress(0);
2967 final State previousState = mState;
2969 mExportProgressDialog.show();
2972 Thread exportThread =
new Thread(
new Runnable() {
2975 final long startTime = System.currentTimeMillis()/1000;
2981 runOnUiThread(
new Runnable() {
2983 if(mExportProgressDialog.isShowing())
2987 AlertDialog
d2 =
new AlertDialog.Builder(getActivity())
2988 .setCancelable(
false)
2989 .setTitle(
"Database saved!")
2990 .setMessage(String.format(
"Database \"%s\" (%d MB) successfully saved!", fileName, fileSizeMB))
2991 .setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
2992 public void onClick(DialogInterface dialog, int which) {
2993 openDatabase(fileName, false);
2997 d2.setCanceledOnTouchOutside(
true);
3002 updateState(previousState);
3003 mToast.makeText(getActivity(), String.format(
"Recovery failed!"), mToast.LENGTH_LONG).show();
3005 mExportProgressDialog.dismiss();
3009 mToast.makeText(getActivity(), String.format(
"Recovery canceled"), mToast.LENGTH_LONG).show();
3010 updateState(previousState);
3016 exportThread.start();
3018 refreshSystemMediaScanDataBase(getActivity(), outputDbPath);
3022 d2.setCanceledOnTouchOutside(
false);
3030 if(!(mState ==
State.STATE_CAMERA || mState ==
State.STATE_MAPPING))
3033 startCamera(String.format(
"Hold Tight! Initializing Camera Service...\n"
3034 +
"Tip: If the camera is still drifting just after the mapping has started, do \"Reset\"."));
3043 if(files.length > 0)
3045 String[] filesWithSize =
new String[files.length];
3046 for(
int i = 0;
i<filesWithSize.length; ++
i)
3048 File filePath =
new File(mWorkingDirectory+files[
i]);
3049 long mb = filePath.length()/(1024*1024);
3050 filesWithSize[
i] = files[
i] +
" ("+mb+
" MB)";
3053 ArrayList<HashMap<String, String> > arrayList =
new ArrayList<HashMap<String, String> >();
3054 for (
int i = 0;
i < filesWithSize.length;
i++) {
3055 HashMap<String, String> hashMap =
new HashMap<String, String>();
3056 hashMap.put(
"name", filesWithSize[
i]);
3057 hashMap.put(
"path", mWorkingDirectory + files[
i]);
3058 arrayList.add(hashMap);
3060 String[] from = {
"name",
"path"};
3061 int[] to = {
R.id.textView,
R.id.imageView};
3064 AlertDialog.Builder builder =
new AlertDialog.Builder(
this);
3065 builder.setCancelable(
true);
3066 builder.setTitle(
"Choose Your File (*.db)");
3067 builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
3068 public void onClick(DialogInterface dialog, int whichIn) {
3072 builder.setAdapter(simpleAdapter,
new DialogInterface.OnClickListener() {
3074 public void onClick(DialogInterface dialog, final int which) {
3077 AlertDialog d2 = new AlertDialog.Builder(getActivity())
3078 .setCancelable(false)
3079 .setTitle(
"Opening database...")
3080 .setMessage(
"Do you want to adjust colors now?\nThis can be done later under Optimize menu.")
3081 .setPositiveButton(
"Yes", new DialogInterface.OnClickListener() {
3082 public void onClick(DialogInterface dialog, int whichIn) {
3083 openDatabase(files[which], true);
3086 .setNeutralButton(
"No", new DialogInterface.OnClickListener() {
3087 public void onClick(DialogInterface dialog, int whichIn) {
3088 openDatabase(files[which], false);
3092 d2.setCanceledOnTouchOutside(false);
3098 final AlertDialog ad = builder.create();
3099 ad.setCanceledOnTouchOutside(
true);
3100 ad.setOnShowListener(
new OnShowListener()
3103 public void onShow(DialogInterface dialog)
3105 ListView lv = ad.getListView();
3106 ad.registerForContextMenu(lv);
3107 lv.setOnCreateContextMenuListener(
new OnCreateContextMenuListener() {
3110 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
3112 if (
v.getId()==ad.getListView().getId()) {
3113 AdapterView.AdapterContextMenuInfo
info = (AdapterView.AdapterContextMenuInfo)menuInfo;
3115 menu.setHeaderTitle(files[position]);
3116 menu.add(Menu.NONE, 0, 0,
"Rename").setOnMenuItemClickListener(
new OnMenuItemClickListener() {
3118 public boolean onMenuItemClick(MenuItem item) {
3119 AlertDialog.Builder builderRename =
new AlertDialog.Builder(getActivity());
3120 builderRename.setCancelable(
false);
3121 builderRename.setTitle(
"RTAB-Map Database Name (*.db):");
3122 final EditText input =
new EditText(getActivity());
3123 input.setInputType(InputType.TYPE_CLASS_TEXT);
3125 input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
3126 input.setSelectAllOnFocus(
true);
3128 builderRename.setView(input);
3129 builderRename.setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
3131 public void onClick(DialogInterface dialog, int which)
3133 final String fileName = input.getText().toString();
3135 if(!fileName.isEmpty())
3137 File newFile = new File(mWorkingDirectory + fileName +
".db");
3138 if(newFile.exists())
3140 AlertDialog d2 = new AlertDialog.Builder(getActivity())
3141 .setCancelable(false)
3142 .setTitle(
"File Already Exists")
3143 .setMessage(String.format(
"Name %s already used, choose another name.", fileName))
3145 d2.setCanceledOnTouchOutside(false);
3150 File from = new File(mWorkingDirectory, files[position]);
3151 File to = new File(mWorkingDirectory, fileName +
".db");
3154 long stamp = System.currentTimeMillis();
3155 if(stamp-mSavedStamp < 10000)
3158 Thread.sleep(10000 - (stamp-mSavedStamp));
3160 catch(InterruptedException e){}
3163 refreshSystemMediaScanDataBase(getActivity(), files[position]);
3164 refreshSystemMediaScanDataBase(getActivity(), to.getAbsolutePath());
3167 resetNoTouchTimer(true);
3172 AlertDialog alertToShow = builderRename.create();
3173 alertToShow.setCanceledOnTouchOutside(
false);
3174 alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
3179 menu.add(Menu.NONE, 1, 1,
"Delete").setOnMenuItemClickListener(
new OnMenuItemClickListener() {
3181 public boolean onMenuItemClick(MenuItem item) {
3182 DialogInterface.OnClickListener dialogClickListener =
new DialogInterface.OnClickListener() {
3184 public void onClick(DialogInterface dialog,
int which) {
3186 case DialogInterface.BUTTON_POSITIVE:
3187 Log.e(TAG, String.format(
"Yes delete %s!", files[position]));
3188 (
new File(mWorkingDirectory+files[position])).
delete();
3189 refreshSystemMediaScanDataBase(getActivity(), mWorkingDirectory+files[position]);
3191 resetNoTouchTimer(
true);
3194 case DialogInterface.BUTTON_NEGATIVE:
3200 AlertDialog dialog =
new AlertDialog.Builder(getActivity())
3201 .setCancelable(
false)
3202 .setTitle(String.format(
"Delete %s", files[position]))
3203 .setMessage(
"Are you sure?")
3204 .setPositiveButton(
"Yes", dialogClickListener)
3205 .setNegativeButton(
"No", dialogClickListener).create();
3206 dialog.setCanceledOnTouchOutside(
false);
3211 menu.add(Menu.NONE, 2, 2,
"Share").setOnMenuItemClickListener(
new OnMenuItemClickListener() {
3213 public boolean onMenuItemClick(MenuItem item) {
3215 if (!PermissionHelper.hasPermission(getActivity(), Manifest.permission.INTERNET)) {
3216 PermissionHelper.requestPermission(getActivity(), Manifest.permission.INTERNET);
3221 File
f =
new File(mWorkingDirectory+files[position]);
3222 final int fileSizeMB = (
int)
f.length()/(1024 * 1024);
3223 Intent shareIntent =
new Intent();
3224 shareIntent.setAction(Intent.ACTION_SEND);
3225 shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
3226 Uri fileUri = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() +
".provider", f);
3227 shareIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
3228 shareIntent.setType(
"application/octet-stream");
3229 startActivity(Intent.createChooser(shareIntent, String.format(
"Sharing database \"%s\" (%d MB)...", files[position], fileSizeMB)));
3231 resetNoTouchTimer(
true);
3244 private void export(
final boolean isOBJ,
final boolean meshing,
final boolean regenerateCloud,
final boolean optimized,
final int optimizedMaxPolygons)
3246 final String extension = isOBJ?
".obj" :
".ply";
3249 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(
this);
3250 final String cloudVoxelSizeStr = sharedPref.getString(getString(
R.string.pref_key_cloud_voxel), getString(
R.string.pref_default_cloud_voxel));
3251 final float cloudVoxelSize =
Float.parseFloat(cloudVoxelSizeStr);
3252 final int textureSize = isOBJ?Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_texture_size), getString(
R.string.pref_default_texture_size))):0;
3253 final int textureCount = Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_texture_count), getString(
R.string.pref_default_texture_count)));
3254 final int normalK = Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_normal_k), getString(
R.string.pref_default_normal_k)));
3255 final float maxTextureDistance =
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_max_texture_distance), getString(
R.string.pref_default_max_texture_distance)));
3256 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)));
3257 final float optimizedVoxelSize = cloudVoxelSize;
3258 final int optimizedDepth = Integer.parseInt(sharedPref.getString(getString(
R.string.pref_key_opt_depth), getString(
R.string.pref_default_opt_depth)));
3259 final float optimizedColorRadius =
Float.parseFloat(sharedPref.getString(getString(
R.string.pref_key_opt_color_radius), getString(
R.string.pref_default_opt_color_radius)));
3260 final boolean optimizedCleanWhitePolygons = sharedPref.getBoolean(getString(
R.string.pref_key_opt_clean_white),
Boolean.parseBoolean(getString(
R.string.pref_default_opt_clean_white)));
3261 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)));
3262 final boolean blockRendering = sharedPref.getBoolean(getString(
R.string.pref_key_block_render),
Boolean.parseBoolean(getString(
R.string.pref_default_block_render)));
3265 mExportProgressDialog.setTitle(
"Exporting");
3266 mExportProgressDialog.setMessage(String.format(
"Please wait while preparing data to export..."));
3267 mExportProgressDialog.setProgress(0);
3269 final State previousState = mState;
3271 mExportProgressDialog.show();
3274 Thread exportThread =
new Thread(
new Runnable() {
3277 final long startTime = System.currentTimeMillis()/1000;
3290 optimizedMaxPolygons,
3291 optimizedColorRadius,
3292 optimizedCleanWhitePolygons,
3293 optimizedMinClusterSize,
3295 minTextureClusterSize,
3297 runOnUiThread(
new Runnable() {
3299 if(mExportProgressDialog.isShowing())
3303 if(!meshing && cloudVoxelSize>0.0
f)
3305 mToast.makeText(getActivity(), String.format(
"Cloud assembled and voxelized at %s m.", cloudVoxelSizeStr), mToast.LENGTH_LONG).show();
3308 final long endTime = System.currentTimeMillis()/1000;
3310 if(endTime-startTime > 10)
3314 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
3315 boolean notifySound = sharedPref.getBoolean(getString(
R.string.pref_key_notification_sound),
Boolean.parseBoolean(getString(
R.string.pref_default_notification_sound)));
3316 Notification
n =
new Notification.Builder(getActivity())
3317 .setContentTitle(getString(
R.string.app_name))
3318 .setContentText(
"Data generated and ready to be exported!")
3319 .setSmallIcon(
R.drawable.ic_launcher)
3320 .setDefaults(notifySound?Notification.DEFAULT_SOUND:0)
3321 .setAutoCancel(
true).build();
3323 NotificationManager notificationManager =
3324 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
3326 notificationManager.notify(0,
n);
3330 resetNoTouchTimer(
true);
3331 mSavedRenderingType = mItemRenderingPointCloud.isChecked()?0:mItemRenderingMesh.isChecked()?1:2;
3334 mItemRenderingPointCloud.setChecked(
true);
3338 mItemRenderingMesh.setChecked(
true);
3342 mItemRenderingTextureMesh.setChecked(
true);
3344 if(!optimizedCleanWhitePolygons)
3346 mButtonLighting.setChecked(
true);
3351 if(mButtonCameraView.getSelectedItemPosition() == 0)
3355 if(mOpenedDatabasePath.isEmpty())
3362 updateState(previousState);
3363 mToast.makeText(getActivity(), String.format(
"Exporting map failed!"), mToast.LENGTH_LONG).show();
3365 mExportProgressDialog.dismiss();
3369 mProgressDialog.dismiss();
3370 mToast.makeText(getActivity(), String.format(
"Export canceled"), mToast.LENGTH_LONG).show();
3371 updateState(previousState);
3377 exportThread.start();
3382 AlertDialog.Builder builder =
new AlertDialog.Builder(
this);
3383 builder.setCancelable(
false);
3384 builder.setTitle(
"RTAB-Map Database Name (*.db):");
3385 final EditText input =
new EditText(
this);
3386 input.setInputType(InputType.TYPE_CLASS_TEXT);
3387 if(mOpenedDatabasePath.isEmpty())
3389 String
timeStamp =
new SimpleDateFormat(
"yyMMdd-HHmmss").format(mDateOnPause);
3394 File
f =
new File(mOpenedDatabasePath);
3395 String
name =
f.getName();
3396 input.setText(
name.substring(0,
name.lastIndexOf(
".")));
3398 input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
3399 input.setSelectAllOnFocus(
true);
3401 builder.setView(input);
3402 builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
3404 public void onClick(DialogInterface dialog, int which)
3409 builder.setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
3411 public void onClick(DialogInterface dialog, int which)
3413 final String fileName = input.getText().toString();
3415 if(!fileName.isEmpty())
3417 File newFile = new File(mWorkingDirectory + fileName +
".db");
3418 if(newFile.exists())
3420 AlertDialog d2 = new AlertDialog.Builder(getActivity())
3421 .setCancelable(false)
3422 .setTitle(
"File Already Exists")
3423 .setMessage(
"Do you want to overwrite the existing file?")
3424 .setPositiveButton(
"Yes", new DialogInterface.OnClickListener() {
3425 public void onClick(DialogInterface dialog, int which) {
3426 saveDatabase(fileName);
3429 .setNegativeButton(
"No", new DialogInterface.OnClickListener() {
3430 public void onClick(DialogInterface dialog, int which) {
3432 resetNoTouchTimer(true);
3436 d2.setCanceledOnTouchOutside(false);
3441 saveDatabase(fileName);
3446 AlertDialog alertToShow = builder.create();
3447 alertToShow.setCanceledOnTouchOutside(
false);
3448 alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
3458 Intent mediaScanIntent =
new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
3459 Uri contentUri = Uri.fromFile(
new File(docPath));
3460 mediaScanIntent.setData(contentUri);
3461 context.sendBroadcast(mediaScanIntent);
3466 final String newDatabasePath = mWorkingDirectory + fileName +
".db";
3467 final String newDatabasePathHuman = mWorkingDirectoryHuman + fileName +
".db";
3468 mProgressDialog.setTitle(
"Saving");
3469 if(mOpenedDatabasePath.equals(newDatabasePath))
3471 mProgressDialog.setMessage(String.format(
"Please wait while updating \"%s\"...", newDatabasePathHuman));
3475 mProgressDialog.setMessage(String.format(
"Please wait while saving \"%s\"...", newDatabasePathHuman));
3477 mProgressDialog.show();
3478 final State previousState = mState;
3480 Thread saveThread =
new Thread(
new Runnable() {
3483 runOnUiThread(
new Runnable() {
3486 if(mOpenedDatabasePath.equals(newDatabasePath))
3488 msg = String.format(
"Database \"%s\" updated.", newDatabasePathHuman);
3492 refreshSystemMediaScanDataBase(getActivity(), newDatabasePath);
3493 mSavedStamp = System.currentTimeMillis();
3494 msg = String.format(
"Database saved to \"%s\".", newDatabasePathHuman);
3500 PendingIntent pIntent = PendingIntent.getActivity(getActivity(), (
int) System.currentTimeMillis(), intent, 0);
3501 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
3502 boolean notifySound = sharedPref.getBoolean(getString(
R.string.pref_key_notification_sound),
Boolean.parseBoolean(getString(
R.string.pref_default_notification_sound)));
3503 Notification
n =
new Notification.Builder(getActivity())
3504 .setContentTitle(getString(
R.string.app_name))
3505 .setContentText(
msg)
3506 .setSmallIcon(
R.drawable.ic_launcher)
3507 .setContentIntent(pIntent)
3508 .setDefaults(notifySound?Notification.DEFAULT_SOUND:0)
3509 .setAutoCancel(
true).build();
3511 NotificationManager notificationManager =
3512 (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
3514 notificationManager.notify(0,
n);
3516 final File
f =
new File(newDatabasePath);
3517 final int fileSizeMB = (
int)
f.length()/(1024 * 1024);
3519 if(!mItemDataRecorderMode.isChecked())
3521 mOpenedDatabasePath = newDatabasePath;
3523 mProgressDialog.dismiss();
3524 updateState(previousState);
3526 AlertDialog
d2 =
new AlertDialog.Builder(getActivity())
3527 .setCancelable(
false)
3528 .setTitle(
"Database saved!")
3529 .setMessage(String.format(
"Database \"%s\" (%d MB) successfully saved!", newDatabasePathHuman, fileSizeMB))
3530 .setPositiveButton(
"OK",
new DialogInterface.OnClickListener() {
3531 public void onClick(DialogInterface dialog, int which) {
3532 resetNoTouchTimer(true);
3536 d2.setCanceledOnTouchOutside(
true);
3547 AlertDialog.Builder builder =
new AlertDialog.Builder(
this);
3548 builder.setTitle(
"Model Name:");
3549 final EditText input =
new EditText(
this);
3550 input.setInputType(InputType.TYPE_CLASS_TEXT);
3551 builder.setView(input);
3552 if(mOpenedDatabasePath.isEmpty())
3554 String
timeStamp =
new SimpleDateFormat(
"yyMMdd-HHmmss").format(mDateOnPause);
3559 File
f =
new File(mOpenedDatabasePath);
3560 String
name =
f.getName();
3561 input.setText(
name.substring(0,
name.lastIndexOf(
".")));
3563 input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
3564 input.setSelectAllOnFocus(
true);
3566 builder.setCancelable(
false);
3567 builder.setNegativeButton(
"Cancel",
new DialogInterface.OnClickListener() {
3569 public void onClick(DialogInterface dialog, int which)
3572 resetNoTouchTimer(true);
3575 builder.setPositiveButton(
"Ok",
new DialogInterface.OnClickListener() {
3577 public void onClick(DialogInterface dialog, int which)
3579 final String fileName = input.getText().toString();
3581 if(!fileName.isEmpty())
3583 writeExportedFiles(fileName);
3587 AlertDialog alertToShow = builder.create();
3588 alertToShow.setCanceledOnTouchOutside(
false);
3589 alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
3595 Log.i(TAG, String.format(
"Write exported mesh to \"%s\"", fileName));
3597 mProgressDialog.setTitle(
"Exporting");
3598 mProgressDialog.setMessage(String.format(
"Compressing the files..."));
3599 mProgressDialog.show();
3601 Thread workingThread =
new Thread(
new Runnable() {
3603 boolean success =
false;
3605 File tmpDir =
new File(mWorkingDirectory + RTABMAP_TMP_DIR);
3607 String[] fileNames =
Util.
loadFileList(mWorkingDirectory + RTABMAP_TMP_DIR,
false);
3608 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Deleting %d files in \"%s\"", fileNames.length, mWorkingDirectory + RTABMAP_TMP_DIR));
3609 for(
int i=0;
i<fileNames.length; ++
i)
3611 File
f =
new File(mWorkingDirectory + RTABMAP_TMP_DIR +
"/" + fileNames[
i]);
3614 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Deleted \"%s\"",
f.getPath()));
3618 if(!DISABLE_LOG) Log.i(TAG, String.format(
"Failed deleting \"%s\"",
f.getPath()));
3621 File exportDir =
new File(mWorkingDirectory + RTABMAP_EXPORT_DIR);
3624 final String pathHuman = mWorkingDirectoryHuman + RTABMAP_EXPORT_DIR + fileName +
".zip";
3625 final String zipOutput = mWorkingDirectory+RTABMAP_EXPORT_DIR+fileName+
".zip";
3629 if(fileNames.length > 0)
3631 String[] filesToZip =
new String[fileNames.length];
3632 for(
int i=0;
i<fileNames.length; ++
i)
3634 filesToZip[
i] = mWorkingDirectory + RTABMAP_TMP_DIR +
"/" + fileNames[
i];
3637 File toZIPFile =
new File(zipOutput);
3642 Util.
zip(filesToZip, zipOutput);
3645 catch(IOException
e)
3647 final String
msg =
e.getMessage();
3648 runOnUiThread(
new Runnable() {
3650 mToast.makeText(getActivity(), String.format(
"Exporting mesh \"%s\" failed! Error=%s", fileName,
msg), mToast.LENGTH_LONG).show();
3659 runOnUiThread(
new Runnable() {
3661 mProgressDialog.dismiss();
3663 final File
f =
new File(zipOutput);
3664 final int fileSizeMB = (
int)
f.length()/(1024 * 1024);
3666 AlertDialog
d =
new AlertDialog.Builder(getActivity())
3667 .setCancelable(
false)
3668 .setTitle(
"Mesh Saved!")
3669 .setMessage(String.format(
"Mesh \"%s\" (%d MB) successfully exported! Share it?", pathHuman, fileSizeMB))
3670 .setPositiveButton(
"Yes",
new DialogInterface.OnClickListener() {
3671 public void onClick(DialogInterface dialog,
int which) {
3673 Intent shareIntent =
new Intent();
3674 shareIntent.setAction(Intent.ACTION_SEND);
3675 shareIntent.putExtra(Intent.EXTRA_STREAM, FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() +
".provider",
f));
3676 shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
3677 shareIntent.setType(
"application/zip");
3678 startActivity(Intent.createChooser(shareIntent,
"Sharing..."));
3680 resetNoTouchTimer(
true);
3683 .setNegativeButton(
"No",
new DialogInterface.OnClickListener() {
3684 public void onClick(DialogInterface dialog,
int which) {
3685 resetNoTouchTimer(
true);
3688 d.setCanceledOnTouchOutside(
false);
3695 runOnUiThread(
new Runnable() {
3697 mProgressDialog.dismiss();
3698 mToast.makeText(getActivity(), String.format(
"Exporting mesh \"%s\" failed! No files found in tmp directory!? Last export may have failed or have been canceled.", fileName), mToast.LENGTH_LONG).show();
3699 resetNoTouchTimer(
true);
3705 workingThread.start();
3710 mOpenedDatabasePath = mWorkingDirectory + fileName;
3712 Log.i(TAG,
"Open database " + mOpenedDatabasePath);
3714 SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity());
3715 final boolean databaseInMemory = sharedPref.getBoolean(getString(
R.string.pref_key_db_in_memory),
Boolean.parseBoolean(getString(
R.string.pref_default_db_in_memory)));
3717 mProgressDialog.setTitle(
"Loading");
3718 mProgressDialog.setMessage(String.format(
"Opening database \"%s\"...", fileName));
3719 mProgressDialog.show();
3722 Thread openThread =
new Thread(
new Runnable() {
3727 runOnUiThread(
new Runnable() {
3732 mProgressDialog.dismiss();
3733 AlertDialog
d =
new AlertDialog.Builder(getActivity())
3734 .setCancelable(
false)
3736 .setMessage(
"The map is loaded but optimization of the map's graph has "
3737 +
"failed, so the map cannot be shown. Change the Graph Optimizer approach used"
3738 +
" or enable/disable if the graph is optimized from graph "
3739 +
"end in \"Settings -> Mapping...\" and try opening again.")
3740 .setPositiveButton(
"Open Settings",
new DialogInterface.OnClickListener() {
3741 public void onClick(DialogInterface dialog, int which) {
3742 Intent intent = new Intent(getActivity(), SettingsActivity.class);
3743 startActivity(intent);
3746 .setNegativeButton(
"Close",
new DialogInterface.OnClickListener() {
3747 public void onClick(DialogInterface dialog, int which) {
3750 d.setCanceledOnTouchOutside(
false);
3753 else if(status == -2)
3756 mProgressDialog.dismiss();
3757 AlertDialog
d =
new AlertDialog.Builder(getActivity())
3758 .setCancelable(
false)
3760 .setMessage(
"Failed to open database: Out of memory! Try "
3761 +
"again after lowering Point Cloud Density in Settings.")
3762 .setPositiveButton(
"Open Settings",
new DialogInterface.OnClickListener() {
3763 public void onClick(DialogInterface dialog, int which) {
3764 Intent intent = new Intent(getActivity(), SettingsActivity.class);
3765 startActivity(intent);
3768 .setNegativeButton(
"Close",
new DialogInterface.OnClickListener() {
3769 public void onClick(DialogInterface dialog, int which) {
3772 d.setCanceledOnTouchOutside(
false);
3777 if(status >= 1 && status<=3)
3779 mProgressDialog.dismiss();
3780 resetNoTouchTimer(
true);
3782 mToast.makeText(getActivity(), String.format(
"Database loaded!"), mToast.LENGTH_LONG).show();
3784 else if(!mItemTrajectoryMode.isChecked())
3786 if(mButtonCameraView.getSelectedItemPosition() == 0)
3792 mProgressDialog.setTitle(
"Loading");
3793 mProgressDialog.setMessage(String.format(
"Database \"%s\" loaded. Please wait while rendering point clouds and meshes...", fileName));
3813 intent.putExtra(RTABMAP_AUTH_TOKEN_KEY, mAuthToken);
3814 intent.putExtra(RTABMAP_WORKING_DIR_KEY, mWorkingDirectory);
3816 if(mOpenedDatabasePath.isEmpty())
3818 intent.putExtra(RTABMAP_FILENAME_KEY,
new SimpleDateFormat(
"yyMMdd-HHmmss").
format(mDateOnPause));
3822 File
f =
new File(mOpenedDatabasePath);
3823 String
name =
f.getName();
3824 intent.putExtra(RTABMAP_FILENAME_KEY,
name.substring(0,
name.lastIndexOf(
".")));
3827 startActivityForResult(intent, SKETCHFAB_ACTIVITY_CODE);