2016-02-15 19:35:24 -05:00
package com.introlab.rtabmap ;
2017-01-26 16:46:24 -05:00
import java.io.BufferedInputStream ;
import java.io.BufferedOutputStream ;
2016-02-15 19:35:24 -05:00
import java.io.File ;
2017-01-26 16:46:24 -05:00
import java.io.FileInputStream ;
import java.io.FileOutputStream ;
2016-02-15 19:35:24 -05:00
import java.io.FilenameFilter ;
2017-01-26 16:46:24 -05:00
import java.io.IOException ;
2017-02-05 17:24:45 -05:00
import java.io.InputStream ;
import java.io.OutputStream ;
2017-02-28 21:50:50 -05:00
import java.lang.reflect.InvocationTargetException ;
import java.lang.reflect.Method ;
2016-11-04 16:39:52 -04:00
import java.text.SimpleDateFormat ;
2017-06-20 17:29:06 -04:00
import java.util.ArrayList ;
2016-11-04 17:03:06 -04:00
import java.util.Arrays ;
2016-11-04 16:39:52 -04:00
import java.util.Date ;
2017-06-20 17:29:06 -04:00
import java.util.HashMap ;
2017-01-26 16:46:24 -05:00
import java.util.List ;
import java.util.zip.ZipEntry ;
import java.util.zip.ZipOutputStream ;
2016-02-15 19:35:24 -05:00
2017-06-21 20:54:16 -04:00
import android.app.ActionBar ;
2016-02-15 19:35:24 -05:00
import android.app.Activity ;
2017-02-05 17:24:45 -05:00
import android.app.ActivityManager ;
import android.app.ActivityManager.MemoryInfo ;
2016-02-15 19:35:24 -05:00
import android.app.AlertDialog ;
2017-01-26 16:46:24 -05:00
import android.app.Dialog ;
2016-02-15 19:35:24 -05:00
import android.app.Notification ;
import android.app.NotificationManager ;
import android.app.PendingIntent ;
import android.app.ProgressDialog ;
2016-05-12 14:34:51 -04:00
import android.content.ComponentName ;
2017-01-26 16:46:24 -05:00
import android.content.Context ;
2016-02-15 19:35:24 -05:00
import android.content.DialogInterface ;
import android.content.Intent ;
2016-05-12 14:34:51 -04:00
import android.content.ServiceConnection ;
2017-01-26 16:46:24 -05:00
import android.content.SharedPreferences ;
2017-03-12 21:21:09 -04:00
import android.content.pm.ApplicationInfo ;
2016-02-15 19:35:24 -05:00
import android.content.pm.PackageInfo ;
import android.content.pm.PackageManager ;
import android.content.pm.PackageManager.NameNotFoundException ;
2017-02-05 17:24:45 -05:00
import android.content.res.Configuration ;
2017-06-20 17:29:06 -04:00
import android.database.Cursor ;
import android.database.sqlite.SQLiteDatabase ;
2017-01-26 16:46:24 -05:00
import android.graphics.Bitmap ;
2017-02-22 09:48:45 -05:00
import android.graphics.Canvas ;
import android.graphics.Color ;
import android.graphics.Paint ;
2017-06-21 20:54:16 -04:00
import android.graphics.Rect ;
2017-02-22 09:48:45 -05:00
import android.graphics.Typeface ;
2017-02-05 17:24:45 -05:00
import android.hardware.Camera ;
2016-02-15 19:35:24 -05:00
import android.graphics.Point ;
2017-02-05 17:24:45 -05:00
import android.hardware.display.DisplayManager ;
import android.net.ConnectivityManager ;
import android.net.NetworkInfo ;
2017-01-26 16:46:24 -05:00
import android.net.Uri ;
2016-02-15 19:35:24 -05:00
import android.opengl.GLSurfaceView ;
2017-01-26 16:46:24 -05:00
import android.os.AsyncTask ;
2016-02-15 19:35:24 -05:00
import android.os.Bundle ;
import android.os.Environment ;
import android.os.Handler ;
import android.os.Debug ;
2016-05-12 14:34:51 -04:00
import android.os.IBinder ;
2017-06-03 20:06:45 -04:00
import android.os.Message ;
2017-01-26 16:46:24 -05:00
import android.preference.PreferenceManager ;
2016-02-15 19:35:24 -05:00
import android.text.Editable ;
2017-02-27 16:53:05 -05:00
import android.text.Html ;
2016-02-15 19:35:24 -05:00
import android.text.InputType ;
2017-02-27 16:53:05 -05:00
import android.text.SpannableString ;
2017-02-22 09:48:45 -05:00
import android.text.TextPaint ;
2017-06-21 20:54:16 -04:00
import android.text.method.HideReturnsTransformationMethod ;
2017-02-27 16:53:05 -05:00
import android.text.method.LinkMovementMethod ;
import android.text.util.Linkify ;
2016-02-15 19:35:24 -05:00
import android.util.Log ;
2017-06-21 20:54:16 -04:00
import android.util.TypedValue ;
2016-02-15 19:35:24 -05:00
import android.view.Display ;
2017-04-17 21:42:01 -04:00
import android.view.GestureDetector ;
2016-02-15 19:35:24 -05:00
import android.view.Menu ;
import android.view.MenuItem ;
import android.view.MenuInflater ;
import android.view.MotionEvent ;
2017-02-05 17:24:45 -05:00
import android.view.Surface ;
2016-02-15 19:35:24 -05:00
import android.view.View ;
import android.view.View.OnClickListener ;
2017-04-17 21:42:01 -04:00
import android.view.View.OnTouchListener ;
2017-06-21 20:54:16 -04:00
import android.view.Window ;
2016-04-04 13:03:43 -04:00
import android.view.WindowManager ;
2017-02-15 19:07:10 -05:00
import android.view.inputmethod.EditorInfo ;
2017-01-26 16:46:24 -05:00
import android.webkit.WebView ;
import android.webkit.WebViewClient ;
2017-06-28 13:59:20 -04:00
import android.widget.AdapterView ;
import android.widget.AdapterView.OnItemSelectedListener ;
import android.widget.ArrayAdapter ;
2017-01-26 16:46:24 -05:00
import android.widget.Button ;
2016-02-15 19:35:24 -05:00
import android.widget.EditText ;
import android.widget.LinearLayout ;
2017-02-28 21:50:50 -05:00
import android.widget.NumberPicker ;
import android.widget.RelativeLayout ;
2017-06-12 15:36:33 -04:00
import android.widget.SeekBar ;
import android.widget.SeekBar.OnSeekBarChangeListener ;
2017-06-28 13:59:20 -04:00
import android.widget.Spinner ;
2016-02-15 19:35:24 -05:00
import android.widget.TextView ;
import android.widget.Toast ;
2017-01-26 16:46:24 -05:00
import android.widget.ToggleButton ;
2016-02-15 19:35:24 -05:00
2016-03-17 22:37:59 -04:00
import com.google.atap.tangoservice.Tango ;
2016-02-15 19:35:24 -05:00
// The main activity of the application. This activity shows debug information
// and a glSurfaceView that renders graphic content.
2017-06-28 13:59:20 -04:00
public class RTABMapActivity extends Activity implements OnClickListener , OnItemSelectedListener {
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
// Tag for debug logging.
public static final String TAG = RTABMapActivity . class . getSimpleName ();
2017-03-12 21:21:09 -04:00
public static boolean DISABLE_LOG = true ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
// The minimum Tango Core version required from this application.
private static final int MIN_TANGO_CORE_VERSION = 9377 ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
// The package name of Tang Core, used for checking minimum Tango Core version.
private static final String TANGO_PACKAGE_NAME = "com.google.tango" ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
public static final String EXTRA_KEY_PERMISSIONTYPE = "PERMISSIONTYPE" ;
public static final String EXTRA_VALUE_ADF = "ADF_LOAD_SAVE_PERMISSION" ;
2017-02-05 17:24:45 -05:00
public static final String RTABMAP_TMP_DB = "rtabmap.tmp.db" ;
2017-06-10 21:45:51 -04:00
public static final String RTABMAP_TMP_DIR = "tmp" ;
2017-02-15 19:07:10 -05:00
public static final String RTABMAP_TMP_FILENAME = "map" ;
2017-02-22 09:48:45 -05:00
public static final String RTABMAP_SDCARD_PATH = "/sdcard/" ;
2017-03-05 13:05:26 -05:00
public static final String RTABMAP_EXPORT_DIR = "Export/" ;
2016-05-12 14:34:51 -04:00
2017-02-15 19:07:10 -05:00
public static final String RTABMAP_AUTH_TOKEN_KEY = "com.introlab.rtabmap.AUTH_TOKEN" ;
public static final String RTABMAP_FILENAME_KEY = "com.introlab.rtabmap.FILENAME" ;
public static final String RTABMAP_OPENED_DB_PATH_KEY = "com.introlab.rtabmap.OPENED_DB_PATH" ;
public static final String RTABMAP_WORKING_DIR_KEY = "com.introlab.rtabmap.WORKING_DIR" ;
public static final int SKETCHFAB_ACTIVITY_CODE = 999 ;
2017-01-26 16:46:24 -05:00
private String mAuthToken ;
2017-06-03 20:06:45 -04:00
public static final long NOTOUCH_TIMEOUT = 5000 ; // 5 sec
private boolean mHudVisible = true ;
2017-06-12 19:08:51 -04:00
private int mSavedRenderingType = 0 ;
2017-06-21 20:54:16 -04:00
private boolean mMenuOpened = false ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
// UI states
private static enum State {
STATE_IDLE ,
STATE_PROCESSING ,
2017-06-20 17:29:06 -04:00
STATE_VISUALIZING ,
STATE_VISUALIZING_WHILE_LOADING
2017-01-26 16:46:24 -05:00
}
State mState = State . STATE_IDLE ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
// GLSurfaceView and renderer, all of the graphic content is rendered
// through OpenGL ES 2.0 in native code.
2017-06-21 20:54:16 -04:00
private Renderer mRenderer = null ;
2017-01-26 16:46:24 -05:00
private GLSurfaceView mGLView ;
2017-06-21 20:54:16 -04:00
View mDecorView ;
int mStatusBarHeight = 0 ;
int mActionBarHeight = 0 ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
ProgressDialog mProgressDialog ;
2017-02-28 21:50:50 -05:00
ProgressDialog mExportProgressDialog ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
// Screen size for normalizing the touch input for orbiting the render camera.
private Point mScreenSize = new Point ();
2017-02-05 17:24:45 -05:00
private long mOnPauseStamp = 0 ;
2017-01-26 16:46:24 -05:00
private boolean mOnPause = false ;
2017-02-15 19:07:10 -05:00
private Date mDateOnPause = new Date ();
2017-02-27 16:53:05 -05:00
private boolean mBlockBack = true ;
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
private MenuItem mItemSave ;
private MenuItem mItemOpen ;
private MenuItem mItemPostProcessing ;
private MenuItem mItemExport ;
private MenuItem mItemSettings ;
private MenuItem mItemModes ;
private MenuItem mItemReset ;
private MenuItem mItemLocalizationMode ;
private MenuItem mItemTrajectoryMode ;
private MenuItem mItemRenderingPointCloud ;
private MenuItem mItemRenderingMesh ;
private MenuItem mItemRenderingTextureMesh ;
private MenuItem mItemDataRecorderMode ;
2017-02-22 09:48:45 -05:00
private MenuItem mItemStatusVisibility ;
private MenuItem mItemDebugVisibility ;
2016-09-08 11:55:44 -04:00
2017-06-28 13:59:20 -04:00
private NDSpinner mButtonCameraView ;
2017-01-26 16:46:24 -05:00
private ToggleButton mButtonPause ;
private ToggleButton mButtonLighting ;
2017-06-12 19:08:51 -04:00
private ToggleButton mButtonWireframe ;
2017-02-15 19:07:10 -05:00
private ToggleButton mButtonBackfaceShown ;
2017-01-27 11:47:57 -05:00
private Button mButtonCloseVisualization ;
2017-02-15 19:07:10 -05:00
private Button mButtonSaveOnDevice ;
private Button mButtonShareOnSketchfab ;
2017-08-03 11:52:18 -04:00
private SeekBar mSeekBarOrthoCut ;
2017-06-28 13:59:20 -04:00
private SeekBar mSeekBarGrid ;
2017-01-26 16:46:24 -05:00
private String mOpenedDatabasePath = "" ;
private String mWorkingDirectory = "" ;
2017-02-22 09:48:45 -05:00
private String mWorkingDirectoryHuman = "" ;
2017-01-26 16:46:24 -05:00
private String mUpdateRate ;
private String mTimeThr ;
private String mMaxFeatures ;
private String mLoopThr ;
2017-02-15 19:07:10 -05:00
private String mMinInliers ;
private String mMaxOptimizationError ;
2017-01-26 16:46:24 -05:00
private int mTotalLoopClosures = 0 ;
private boolean mMapIsEmpty = false ;
2017-03-12 21:21:09 -04:00
int mMapNodes = 0 ;
2017-01-26 16:46:24 -05:00
private Toast mToast = null ;
2017-02-15 19:07:10 -05:00
2017-02-22 09:48:45 -05:00
private AlertDialog mMemoryWarningDialog = null ;
private String [] mStatusTexts = new String [ 16 ] ;
2017-04-17 21:42:01 -04:00
GestureDetector mGesDetect = null ;
2017-01-26 16:46:24 -05:00
//Tango Service connection.
ServiceConnection mTangoServiceConnection = new ServiceConnection () {
2017-02-05 17:24:45 -05:00
public void onServiceConnected ( ComponentName name , final IBinder service ) {
Thread bindThread = new Thread ( new Runnable () {
public void run () {
if ( ! RTABMapLib . onTangoServiceConnected ( service ))
{
runOnUiThread ( new Runnable () {
public void run () {
mToast . makeText ( getApplicationContext (),
String . format ( "Failed to intialize Tango!" ), mToast . LENGTH_LONG ). show ();
}
});
}
}
});
bindThread . start ();
2017-01-26 16:46:24 -05:00
}
public void onServiceDisconnected ( ComponentName name ) {
// Handle this if you need to gracefully shutdown/retry
// in the event that Tango itself crashes/gets upgraded while running.
mToast . makeText ( getApplicationContext (),
2017-02-05 17:24:45 -05:00
String . format ( "Tango disconnected!" ), mToast . LENGTH_LONG ). show ();
2017-01-26 16:46:24 -05:00
}
};
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState );
setTitle ( R . string . menu_name );
// Query screen size, the screen size is used for computing the normalized
// touch point.
Display display = getWindowManager (). getDefaultDisplay ();
display . getSize ( mScreenSize );
getWindow (). addFlags ( WindowManager . LayoutParams . FLAG_KEEP_SCREEN_ON );
2017-07-24 20:24:16 -04:00
getWindow (). addFlags ( WindowManager . LayoutParams . FLAG_TRANSLUCENT_STATUS );
2017-06-21 20:54:16 -04:00
2017-01-26 16:46:24 -05:00
// Setting content view of this activity.
setContentView ( R . layout . activity_rtabmap );
2017-06-21 20:54:16 -04:00
2017-01-26 16:46:24 -05:00
// Make sure to initialize all default values
SettingsActivity settings ;
2017-06-21 20:54:16 -04:00
mDecorView = getWindow (). getDecorView ();
mStatusBarHeight = getStatusBarHeight ();
mActionBarHeight = getActionBarHeight ();
2017-01-26 16:46:24 -05:00
// Buttons for selecting camera view and Set up button click listeners.
2017-06-28 13:59:20 -04:00
mButtonCameraView = ( NDSpinner ) findViewById ( R . id . camera_button );
2017-01-26 16:46:24 -05:00
mButtonPause = ( ToggleButton ) findViewById ( R . id . pause_button );
mButtonLighting = ( ToggleButton ) findViewById ( R . id . light_button );
2017-06-12 19:08:51 -04:00
mButtonWireframe = ( ToggleButton ) findViewById ( R . id . wireframe_button );
2017-02-15 19:07:10 -05:00
mButtonBackfaceShown = ( ToggleButton ) findViewById ( R . id . backface_button );
2017-01-27 11:47:57 -05:00
mButtonCloseVisualization = ( Button ) findViewById ( R . id . close_visualization_button );
2017-02-15 19:07:10 -05:00
mButtonSaveOnDevice = ( Button ) findViewById ( R . id . button_saveOnDevice );
mButtonShareOnSketchfab = ( Button ) findViewById ( R . id . button_shareToSketchfab );
2017-06-28 13:59:20 -04:00
mButtonCameraView . setOnItemSelectedListener ( this );
2017-01-26 16:46:24 -05:00
mButtonPause . setOnClickListener ( this );
mButtonLighting . setOnClickListener ( this );
2017-06-12 19:08:51 -04:00
mButtonWireframe . setOnClickListener ( this );
2017-02-15 19:07:10 -05:00
mButtonBackfaceShown . setOnClickListener ( this );
2017-01-27 11:47:57 -05:00
mButtonCloseVisualization . setOnClickListener ( this );
2017-02-15 19:07:10 -05:00
mButtonSaveOnDevice . setOnClickListener ( this );
mButtonShareOnSketchfab . setOnClickListener ( this );
2017-04-09 20:00:23 -04:00
mButtonLighting . setChecked ( false );
2017-01-26 16:46:24 -05:00
mButtonLighting . setVisibility ( View . INVISIBLE );
2017-06-12 19:08:51 -04:00
mButtonWireframe . setChecked ( false );
mButtonWireframe . setVisibility ( View . INVISIBLE );
2017-01-27 11:47:57 -05:00
mButtonCloseVisualization . setVisibility ( View . INVISIBLE );
2017-02-15 19:07:10 -05:00
mButtonSaveOnDevice . setVisibility ( View . INVISIBLE );
mButtonShareOnSketchfab . setVisibility ( View . INVISIBLE );
if ( mItemRenderingMesh != null && mItemRenderingTextureMesh != null )
{
mButtonBackfaceShown . setVisibility ( mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked () ? View . VISIBLE : View . INVISIBLE );
}
2017-06-12 15:36:33 -04:00
2017-06-28 13:59:20 -04:00
ArrayAdapter < CharSequence > adapter = ArrayAdapter . createFromResource ( this , R . array . camera_view_array , android . R . layout . simple_spinner_item );
adapter . setDropDownViewResource ( android . R . layout . simple_spinner_dropdown_item );
mButtonCameraView . setAdapter ( adapter );
mButtonCameraView . setOnTouchListener ( new OnTouchListener () {
@Override
public boolean onTouch ( View v , MotionEvent event ) {
resetNoTouchTimer ();
return false ;
}
});
2017-08-03 11:52:18 -04:00
mSeekBarOrthoCut = ( SeekBar ) findViewById ( R . id . seekBar_ortho_cut );
mSeekBarOrthoCut . setMax ( 120 );
mSeekBarOrthoCut . setProgress ( 80 );
mSeekBarOrthoCut . setOnSeekBarChangeListener ( new OnSeekBarChangeListener () {
2017-06-12 15:36:33 -04:00
@Override
public void onProgressChanged ( SeekBar seekBar , int progressValue , boolean fromUser ) {
2017-08-03 11:52:18 -04:00
RTABMapLib . setOrthoCropFactor (( float )( 120 - progressValue ) / 20 . 0f - 3 . 0f );
2017-06-12 15:36:33 -04:00
resetNoTouchTimer ();
}
@Override
public void onStartTrackingTouch ( SeekBar seekBar ) {
}
@Override
public void onStopTrackingTouch ( SeekBar seekBar ) {
}
});
2017-06-28 13:59:20 -04:00
mSeekBarGrid = ( SeekBar ) findViewById ( R . id . seekBar_grid );
mSeekBarGrid . setMax ( 180 );
mSeekBarGrid . setProgress ( 90 );
mSeekBarGrid . setOnSeekBarChangeListener ( new OnSeekBarChangeListener () {
@Override
public void onProgressChanged ( SeekBar seekBar , int progressValue , boolean fromUser ) {
RTABMapLib . setGridRotation ((( float ) progressValue - 90 . 0f ) / 2 . 0f );
resetNoTouchTimer ();
}
@Override
public void onStartTrackingTouch ( SeekBar seekBar ) {
}
@Override
public void onStopTrackingTouch ( SeekBar seekBar ) {
}
});
2017-01-26 16:46:24 -05:00
mToast = Toast . makeText ( getApplicationContext (), "" , Toast . LENGTH_SHORT );
// OpenGL view where all of the graphics are drawn.
mGLView = ( GLSurfaceView ) findViewById ( R . id . gl_surface_view );
2017-04-17 21:42:01 -04:00
mGesDetect = new GestureDetector ( this , new DoubleTapGestureDetector ());
2017-01-26 16:46:24 -05:00
// Configure OpenGL renderer
mGLView . setEGLContextClientVersion ( 2 );
2017-04-17 21:42:01 -04:00
mGLView . setEGLConfigChooser ( 8 , 8 , 8 , 8 , 24 , 0 );
mGLView . setOnTouchListener ( new OnTouchListener () {
@Override
public boolean onTouch ( View v , MotionEvent event ) {
2017-06-03 20:06:45 -04:00
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( getActionBar (). isShowing () && mHudVisible == false );
2017-06-03 20:06:45 -04:00
2017-04-17 21:42:01 -04:00
mGesDetect . onTouchEvent ( event );
// Pass the touch event to the native layer for camera control.
// Single touch to rotate the camera around the device.
// Two fingers to zoom in and out.
int pointCount = event . getPointerCount ();
if ( pointCount == 1 ) {
float normalizedX = event . getX ( 0 ) / mScreenSize . x ;
float normalizedY = event . getY ( 0 ) / mScreenSize . y ;
RTABMapLib . onTouchEvent ( 1 ,
event . getActionMasked (), normalizedX , normalizedY , 0 . 0f , 0 . 0f );
}
if ( pointCount == 2 ) {
if ( event . getActionMasked () == MotionEvent . ACTION_POINTER_UP ) {
int index = event . getActionIndex () == 0 ? 1 : 0 ;
float normalizedX = event . getX ( index ) / mScreenSize . x ;
float normalizedY = event . getY ( index ) / mScreenSize . y ;
RTABMapLib . onTouchEvent ( 1 ,
MotionEvent . ACTION_DOWN , normalizedX , normalizedY , 0 . 0f , 0 . 0f );
} else {
float normalizedX0 = event . getX ( 0 ) / mScreenSize . x ;
float normalizedY0 = event . getY ( 0 ) / mScreenSize . y ;
float normalizedX1 = event . getX ( 1 ) / mScreenSize . x ;
float normalizedY1 = event . getY ( 1 ) / mScreenSize . y ;
RTABMapLib . onTouchEvent ( 2 , event . getActionMasked (),
normalizedX0 , normalizedY0 , normalizedX1 , normalizedY1 );
}
}
return true ;
}
});
2017-06-21 20:54:16 -04:00
2017-01-26 16:46:24 -05:00
// Configure the OpenGL renderer.
2017-02-05 17:24:45 -05:00
mRenderer = new Renderer ( this );
2017-01-26 16:46:24 -05:00
mGLView . setRenderer ( mRenderer );
mProgressDialog = new ProgressDialog ( this );
mProgressDialog . setCanceledOnTouchOutside ( false );
mRenderer . setProgressDialog ( mProgressDialog );
2017-02-22 09:48:45 -05:00
mRenderer . setToast ( mToast );
2017-06-21 20:54:16 -04:00
setNavVisibility ( true );
2017-02-28 21:50:50 -05:00
mExportProgressDialog = new ProgressDialog ( this );
mExportProgressDialog . setCanceledOnTouchOutside ( false );
mExportProgressDialog . setCancelable ( false );
mExportProgressDialog . setProgressStyle ( ProgressDialog . STYLE_HORIZONTAL );
mExportProgressDialog . setProgressNumberFormat ( null );
mExportProgressDialog . setProgressPercentFormat ( null );
mExportProgressDialog . setButton ( DialogInterface . BUTTON_NEGATIVE , "Cancel" , new DialogInterface . OnClickListener () {
@Override
public void onClick ( DialogInterface dialog , int which ) {
RTABMapLib . cancelProcessing ();
}
});
2017-01-26 16:46:24 -05:00
// Check if the Tango Core is out dated.
if ( ! CheckTangoCoreVersion ( MIN_TANGO_CORE_VERSION )) {
mToast . makeText ( this , "Tango Core out dated, please update in Play Store" , mToast . LENGTH_LONG ). show ();
finish ();
return ;
}
mOpenedDatabasePath = "" ;
mWorkingDirectory = "" ;
2017-02-22 09:48:45 -05:00
mWorkingDirectoryHuman = "" ;
2017-01-26 16:46:24 -05:00
mTotalLoopClosures = 0 ;
if ( Environment . getExternalStorageState (). compareTo ( Environment . MEDIA_MOUNTED ) == 0 )
{
File extStore = Environment . getExternalStorageDirectory ();
mWorkingDirectory = extStore . getAbsolutePath () + "/" + getString ( R . string . app_name ) + "/" ;
extStore = new File ( mWorkingDirectory );
extStore . mkdirs ();
2017-02-22 09:48:45 -05:00
mWorkingDirectoryHuman = RTABMAP_SDCARD_PATH + getString ( R . string . app_name ) + "/" ;
2017-01-26 16:46:24 -05:00
}
else
{
// show warning that data cannot be saved!
mToast . makeText ( getApplicationContext (),
String . format ( "Failed to get external storage path (SD-CARD, state=%s). Saving disabled." ,
Environment . getExternalStorageState ()), mToast . LENGTH_LONG ). show ();
}
RTABMapLib . onCreate ( this );
2017-02-05 17:24:45 -05:00
String tmpDatabase = mWorkingDirectory + RTABMAP_TMP_DB ;
( new File ( tmpDatabase )). delete ();
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
boolean databaseInMemory = sharedPref . getBoolean ( getString ( R . string . pref_key_db_in_memory ), Boolean . parseBoolean ( getString ( R . string . pref_default_db_in_memory )));
RTABMapLib . openDatabase ( tmpDatabase , databaseInMemory , false );
DisplayManager displayManager = ( DisplayManager ) getSystemService ( DISPLAY_SERVICE );
if ( displayManager != null ) {
displayManager . registerDisplayListener ( new DisplayManager . DisplayListener () {
@Override
public void onDisplayAdded ( int displayId ) {
}
@Override
public void onDisplayChanged ( int displayId ) {
synchronized ( this ) {
setAndroidOrientation ();
2017-04-17 21:42:01 -04:00
Display display = getWindowManager (). getDefaultDisplay ();
display . getSize ( mScreenSize );
2017-02-05 17:24:45 -05:00
}
}
@Override
public void onDisplayRemoved ( int displayId ) {}
}, null );
}
2017-06-21 20:54:16 -04:00
2017-03-12 21:21:09 -04:00
DISABLE_LOG = ! ( 0 != ( getApplicationInfo (). flags & ApplicationInfo . FLAG_DEBUGGABLE ) );
2017-01-26 16:46:24 -05:00
}
2017-06-21 20:54:16 -04:00
public int getStatusBarHeight () {
int result = 0 ;
int resourceId = getResources (). getIdentifier ( "status_bar_height" , "dimen" , "android" );
if ( resourceId > 0 ) {
result = getResources (). getDimensionPixelSize ( resourceId );
}
return result ;
}
public int getActionBarHeight () {
int result = 0 ;
TypedValue tv = new TypedValue ();
if ( getTheme (). resolveAttribute ( android . R . attr . actionBarSize , tv , true ))
{
result = TypedValue . complexToDimensionPixelSize ( tv . data , getResources (). getDisplayMetrics ());
}
return result ;
}
@Override
public void onWindowFocusChanged ( boolean hasFocus ) {
super . onWindowFocusChanged ( hasFocus );
if ( ! mHudVisible )
{
mRenderer . setOffset ( ! hasFocus ?- mStatusBarHeight : 0 );
}
}
// This snippet hides the system bars.
private void setNavVisibility ( boolean visible ) {
int newVis = View . SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View . SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View . SYSTEM_UI_FLAG_LAYOUT_STABLE ;
if ( ! visible ) {
newVis |= View . SYSTEM_UI_FLAG_LOW_PROFILE
| View . SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
| View . SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
| View . SYSTEM_UI_FLAG_IMMERSIVE ;
mRenderer . setOffset ( ! hasWindowFocus () ?- mStatusBarHeight : 0 );
}
else
{
mRenderer . setOffset ( - mStatusBarHeight - mActionBarHeight );
}
// Set the new desired visibility.
mDecorView . setSystemUiVisibility ( newVis );
}
2017-01-26 16:46:24 -05:00
@Override
protected void onActivityResult ( int requestCode , int resultCode , Intent data ) {
// Check which request we're responding to
if ( requestCode == Tango . TANGO_INTENT_ACTIVITYCODE ) {
// Make sure the request was successful
if ( resultCode == RESULT_CANCELED ) {
2017-06-21 20:54:16 -04:00
mToast . makeText ( this , "Motion Tracking Permissions Required!" , mToast . LENGTH_SHORT ). show ();
2017-01-26 16:46:24 -05:00
finish ();
}
}
2017-02-15 19:07:10 -05:00
else if ( requestCode == SKETCHFAB_ACTIVITY_CODE ) {
// Make sure the request was successful
if ( resultCode == RESULT_OK ) {
mAuthToken = data . getStringExtra ( RTABMAP_AUTH_TOKEN_KEY );
}
}
2017-01-26 16:46:24 -05:00
}
2017-02-05 17:24:45 -05:00
2017-06-21 20:54:16 -04:00
@Override
public boolean onMenuOpened ( int featureId , Menu menu ) {
mMenuOpened = true ;
return super . onMenuOpened ( featureId , menu );
}
@Override
public void onPanelClosed ( int featureId , Menu menu ) {
mMenuOpened = false ;
}
2017-02-27 16:53:05 -05:00
@Override
public void onBackPressed () {
if ( mBlockBack )
{
mToast . makeText ( this , "Press Back once more to exit" , mToast . LENGTH_LONG ). show ();
mBlockBack = false ;
}
else
{
super . onBackPressed ();
}
}
2017-02-05 17:24:45 -05:00
@Override
protected void onPause () {
super . onPause ();
2017-06-03 20:06:45 -04:00
stopDisconnectTimer ();
2017-02-05 17:24:45 -05:00
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , "onPause()" );
2017-02-05 17:24:45 -05:00
mOnPause = true ;
// This deletes OpenGL context!
mGLView . onPause ();
RTABMapLib . onPause ();
unbindService ( mTangoServiceConnection );
if ( ! mButtonPause . isChecked ())
{
mButtonPause . setChecked ( true );
pauseMapping ();
}
mOnPauseStamp = System . currentTimeMillis () / 1000 ;
}
2017-01-26 16:46:24 -05:00
@Override
protected void onResume () {
super . onResume ();
2017-01-26 17:34:15 -05:00
2017-02-05 17:24:45 -05:00
mProgressDialog . setTitle ( "" );
if ( mOnPause )
2017-01-26 16:46:24 -05:00
{
2017-02-05 17:24:45 -05:00
if ( System . currentTimeMillis () / 1000 - mOnPauseStamp < 1 )
2017-01-26 16:46:24 -05:00
{
2017-02-05 17:24:45 -05:00
mProgressDialog . setMessage ( String . format ( "RTAB-Map has been interrupted by another application, Tango should be re-initialized! Set your phone/tablet in Airplane mode if this happens often." ));
2017-01-26 16:46:24 -05:00
}
else
{
2017-02-05 17:24:45 -05:00
mProgressDialog . setMessage ( String . format ( "Hold Tight! Initializing Tango Service..." ));
2017-01-26 16:46:24 -05:00
}
mToast . makeText ( this , "Mapping is paused!" , mToast . LENGTH_LONG ). show ();
}
else
{
2017-02-05 17:24:45 -05:00
mProgressDialog . setMessage ( String . format ( "Hold Tight! Initializing Tango Service...\nTip: If the camera is still drifting just after the mapping has started, do \"Reset\"." ));
2017-01-26 16:46:24 -05:00
}
2017-02-05 17:24:45 -05:00
mProgressDialog . show ();
2017-01-26 16:46:24 -05:00
mOnPause = false ;
2017-02-05 17:24:45 -05:00
setAndroidOrientation ();
2017-01-26 16:46:24 -05:00
2017-02-05 17:24:45 -05:00
// update preferences
try
{
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . d ( TAG , "update preferences..." );
2017-02-05 17:24:45 -05:00
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
mUpdateRate = sharedPref . getString ( getString ( R . string . pref_key_update_rate ), getString ( R . string . pref_default_update_rate ));
mTimeThr = sharedPref . getString ( getString ( R . string . pref_key_time_thr ), getString ( R . string . pref_default_time_thr ));
String memThr = sharedPref . getString ( getString ( R . string . pref_key_mem_thr ), getString ( R . string . pref_default_mem_thr ));
mLoopThr = sharedPref . getString ( getString ( R . string . pref_key_loop_thr ), getString ( R . string . pref_default_loop_thr ));
String simThr = sharedPref . getString ( getString ( R . string . pref_key_sim_thr ), getString ( R . string . pref_default_sim_thr ));
2017-02-15 19:07:10 -05:00
mMinInliers = sharedPref . getString ( getString ( R . string . pref_key_min_inliers ), getString ( R . string . pref_default_min_inliers ));
mMaxOptimizationError = sharedPref . getString ( getString ( R . string . pref_key_opt_error ), getString ( R . string . pref_default_opt_error ));
2017-02-05 17:24:45 -05:00
mMaxFeatures = sharedPref . getString ( getString ( R . string . pref_key_features_voc ), getString ( R . string . pref_default_features_voc ));
String maxFeaturesLoop = sharedPref . getString ( getString ( R . string . pref_key_features ), getString ( R . string . pref_default_features ));
String featureType = sharedPref . getString ( getString ( R . string . pref_key_features_type ), getString ( R . string . pref_default_features_type ));
boolean keepAllDb = sharedPref . getBoolean ( getString ( R . string . pref_key_keep_all_db ), Boolean . parseBoolean ( getString ( R . string . pref_default_keep_all_db )));
2017-02-15 19:07:10 -05:00
boolean optimizeFromGraphEnd = sharedPref . getBoolean ( getString ( R . string . pref_key_optimize_end ), Boolean . parseBoolean ( getString ( R . string . pref_default_optimize_end )));
String optimizer = sharedPref . getString ( getString ( R . string . pref_key_optimizer ), getString ( R . string . pref_default_optimizer ));
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . d ( TAG , "set mapping parameters" );
2017-04-17 21:42:01 -04:00
RTABMapLib . setOnlineBlending ( sharedPref . getBoolean ( getString ( R . string . pref_key_blending ), Boolean . parseBoolean ( getString ( R . string . pref_default_blending ))));
2017-02-05 17:24:45 -05:00
RTABMapLib . setNodesFiltering ( sharedPref . getBoolean ( getString ( R . string . pref_key_nodes_filtering ), Boolean . parseBoolean ( getString ( R . string . pref_default_nodes_filtering ))));
RTABMapLib . setRawScanSaved ( sharedPref . getBoolean ( getString ( R . string . pref_key_raw_scan_saved ), Boolean . parseBoolean ( getString ( R . string . pref_default_raw_scan_saved ))));
RTABMapLib . setFullResolution ( sharedPref . getBoolean ( getString ( R . string . pref_key_resolution ), Boolean . parseBoolean ( getString ( R . string . pref_default_resolution ))));
2017-02-22 09:48:45 -05:00
RTABMapLib . setSmoothing ( sharedPref . getBoolean ( getString ( R . string . pref_key_smoothing ), Boolean . parseBoolean ( getString ( R . string . pref_default_smoothing ))));
2017-03-13 20:51:59 -04:00
RTABMapLib . setCameraColor ( ! sharedPref . getBoolean ( getString ( R . string . pref_key_fisheye ), Boolean . parseBoolean ( getString ( R . string . pref_default_fisheye ))));
2017-02-05 17:24:45 -05:00
RTABMapLib . setAppendMode ( sharedPref . getBoolean ( getString ( R . string . pref_key_append ), Boolean . parseBoolean ( getString ( R . string . pref_default_append ))));
RTABMapLib . setMappingParameter ( "Rtabmap/DetectionRate" , mUpdateRate );
RTABMapLib . setMappingParameter ( "Rtabmap/TimeThr" , mTimeThr );
RTABMapLib . setMappingParameter ( "Rtabmap/MemoryThr" , memThr );
RTABMapLib . setMappingParameter ( "Mem/RehearsalSimilarity" , simThr );
RTABMapLib . setMappingParameter ( "Kp/MaxFeatures" , mMaxFeatures );
RTABMapLib . setMappingParameter ( "Vis/MaxFeatures" , maxFeaturesLoop );
2017-02-15 19:07:10 -05:00
RTABMapLib . setMappingParameter ( "Vis/MinInliers" , mMinInliers );
2017-02-05 17:24:45 -05:00
RTABMapLib . setMappingParameter ( "Rtabmap/LoopThr" , mLoopThr );
2017-02-15 19:07:10 -05:00
RTABMapLib . setMappingParameter ( "RGBD/OptimizeMaxError" , mMaxOptimizationError );
2017-02-05 17:24:45 -05:00
RTABMapLib . setMappingParameter ( "Kp/DetectorStrategy" , featureType );
RTABMapLib . setMappingParameter ( "Vis/FeatureType" , featureType );
RTABMapLib . setMappingParameter ( "Mem/NotLinkedNodesKept" , String . valueOf ( keepAllDb ));
2017-02-15 19:07:10 -05:00
RTABMapLib . setMappingParameter ( "RGBD/OptimizeFromGraphEnd" , String . valueOf ( optimizeFromGraphEnd ));
RTABMapLib . setMappingParameter ( "Optimizer/Strategy" , optimizer );
2017-02-05 17:24:45 -05:00
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . d ( TAG , "set exporting parameters..." );
2017-03-15 17:05:19 -04:00
RTABMapLib . setCloudDensityLevel ( Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_density ), getString ( R . string . pref_default_density ))));
2017-02-05 17:24:45 -05:00
RTABMapLib . setMaxCloudDepth ( Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_depth ), getString ( R . string . pref_default_depth ))));
2017-04-01 14:14:36 -04:00
RTABMapLib . setMinCloudDepth ( Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_min_depth ), getString ( R . string . pref_default_min_depth ))));
2017-02-05 17:24:45 -05:00
RTABMapLib . setPointSize ( Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_point_size ), getString ( R . string . pref_default_point_size ))));
RTABMapLib . setMeshAngleTolerance ( Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_angle ), getString ( R . string . pref_default_angle ))));
RTABMapLib . setMeshTriangleSize ( Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_triangle ), getString ( R . string . pref_default_triangle ))));
2017-04-17 21:42:01 -04:00
float bgColor = Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_background_color ), getString ( R . string . pref_default_background_color )));
RTABMapLib . setBackgroundColor ( bgColor );
2017-04-18 17:30:14 -04:00
mRenderer . setTextColor ( bgColor >= 0 . 6f ? 0 . 0f : 1 . 0f );
2017-02-05 17:24:45 -05:00
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . d ( TAG , "set rendering parameters..." );
RTABMapLib . setClusterRatio ( Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_cluster_ratio ), getString ( R . string . pref_default_cluster_ratio ))));
2017-02-05 17:24:45 -05:00
RTABMapLib . setMaxGainRadius ( Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_gain_max_radius ), getString ( R . string . pref_default_gain_max_radius ))));
2017-03-12 21:21:09 -04:00
RTABMapLib . setRenderingTextureDecimation ( Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_rendering_texture_decimation ), getString ( R . string . pref_default_rendering_texture_decimation ))));
2017-02-05 17:24:45 -05:00
if ( mItemRenderingPointCloud != null )
{
int renderingType = sharedPref . getInt ( getString ( R . string . pref_key_rendering ), Integer . parseInt ( getString ( R . string . pref_default_rendering )));
if ( renderingType == 0 )
{
mItemRenderingPointCloud . setChecked ( true );
}
else if ( renderingType == 1 )
{
mItemRenderingMesh . setChecked ( true );
}
else
{
mItemRenderingTextureMesh . setChecked ( true );
}
RTABMapLib . setMeshRendering (
mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked (),
mItemRenderingTextureMesh . isChecked ());
2017-02-15 19:07:10 -05:00
mButtonBackfaceShown . setVisibility ( mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked () ? View . VISIBLE : View . INVISIBLE );
2017-02-05 17:24:45 -05:00
}
}
catch ( Exception e )
{
Log . e ( TAG , "Error parsing preferences: " + e . getMessage ());
mToast . makeText ( this , String . format ( "Error parsing preferences: " + e . getMessage ()), mToast . LENGTH_LONG ). show ();
}
2017-01-26 16:46:24 -05:00
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "onResume()" ));
2017-01-26 16:46:24 -05:00
if ( Tango . hasPermission ( this , Tango . PERMISSIONTYPE_MOTION_TRACKING )) {
mGLView . onResume ();
} else {
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "Asking for motion tracking permission" ));
2017-01-26 16:46:24 -05:00
startActivityForResult (
Tango . getRequestPermissionIntent ( Tango . PERMISSIONTYPE_MOTION_TRACKING ),
Tango . TANGO_INTENT_ACTIVITYCODE );
}
2017-02-05 17:24:45 -05:00
TangoInitializationHelper . bindTangoService ( getActivity (), mTangoServiceConnection );
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-01-26 16:46:24 -05:00
}
2017-02-05 17:24:45 -05:00
2017-01-26 16:46:24 -05:00
private void setCamera ( int type )
2017-06-12 15:36:33 -04:00
{
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "called setCamera(type=%d);" , type ));
2017-02-22 09:48:45 -05:00
// for convenience, for a refresh of the memory used
mStatusTexts [ 1 ] = getString ( R . string . memory ) + String . valueOf ( Debug . getNativeHeapAllocatedSize () / ( 1024 * 1024 ));
mStatusTexts [ 2 ] = getString ( R . string . free_memory ) + String . valueOf ( getFreeMemory ());
updateStatusTexts ();
2017-06-12 15:36:33 -04:00
2017-01-26 16:46:24 -05:00
RTABMapLib . setCamera ( type );
2017-06-28 13:59:20 -04:00
mButtonCameraView . setSelection ( type , true );
2017-08-03 11:52:18 -04:00
mSeekBarOrthoCut . setVisibility ( type != 3 ? View . INVISIBLE : View . VISIBLE );
2017-06-28 13:59:20 -04:00
mSeekBarGrid . setVisibility ( mSeekBarGrid . isEnabled () && type == 3 ? View . VISIBLE : View . INVISIBLE );
2017-06-12 15:36:33 -04:00
if ( type == 3 )
{
2017-08-03 11:52:18 -04:00
mSeekBarOrthoCut . setMax ( 120 );
mSeekBarOrthoCut . setProgress ( 80 );
2017-06-12 15:36:33 -04:00
}
2016-09-08 11:55:44 -04:00
}
2017-01-26 16:46:24 -05:00
@Override
public void onClick ( View v ) {
// Handle button clicks.
switch ( v . getId ()) {
2017-08-03 11:52:18 -04:00
case R . id . gl_surface_view :
break ;
2017-01-26 16:46:24 -05:00
case R . id . pause_button :
pauseMapping ();
break ;
case R . id . light_button :
RTABMapLib . setLighting ( mButtonLighting . isChecked ());
break ;
2017-02-15 19:07:10 -05:00
case R . id . backface_button :
RTABMapLib . setBackfaceCulling ( ! mButtonBackfaceShown . isChecked ());
break ;
2017-06-12 19:08:51 -04:00
case R . id . wireframe_button :
RTABMapLib . setWireframe ( mButtonWireframe . isChecked ());
break ;
2017-01-27 11:47:57 -05:00
case R . id . close_visualization_button :
2017-06-12 19:08:51 -04:00
if ( mSavedRenderingType == 0 )
{
mItemRenderingPointCloud . setChecked ( true );
}
else if ( mSavedRenderingType == 1 )
{
mItemRenderingMesh . setChecked ( true );
}
else
{
mItemRenderingTextureMesh . setChecked ( true );
}
2017-01-27 11:47:57 -05:00
updateState ( State . STATE_IDLE );
2017-06-10 21:45:51 -04:00
RTABMapLib . postExportation ( false );
2017-01-27 11:47:57 -05:00
break ;
2017-02-15 19:07:10 -05:00
case R . id . button_saveOnDevice :
saveOnDevice ();
break ;
case R . id . button_shareToSketchfab :
shareToSketchfab ();
break ;
2017-01-26 16:46:24 -05:00
default :
return ;
}
2017-06-03 20:06:45 -04:00
resetNoTouchTimer ();
2017-01-26 16:46:24 -05:00
}
2017-06-28 13:59:20 -04:00
public void onItemSelected ( AdapterView <?> parent , View view , int pos , long id ) {
setCamera ( pos );
resetNoTouchTimer ();
}
public void onNothingSelected ( AdapterView <?> parent ) {
resetNoTouchTimer ();
}
2017-06-21 20:54:16 -04:00
2017-02-05 17:24:45 -05:00
private void setAndroidOrientation () {
Display display = getWindowManager (). getDefaultDisplay ();
Camera . CameraInfo colorCameraInfo = new Camera . CameraInfo ();
2017-03-13 20:51:59 -04:00
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
boolean fisheye = sharedPref . getBoolean ( getString ( R . string . pref_key_fisheye ), Boolean . parseBoolean ( getString ( R . string . pref_default_fisheye )));
Camera . getCameraInfo ( fisheye ? 1 : 0 , colorCameraInfo );
2017-02-05 17:24:45 -05:00
RTABMapLib . setScreenRotation ( display . getRotation (), colorCameraInfo . orientation );
}
2017-04-17 21:42:01 -04:00
class DoubleTapGestureDetector extends GestureDetector . SimpleOnGestureListener {
2017-01-26 16:46:24 -05:00
2017-04-17 21:42:01 -04:00
@Override
public boolean onDoubleTap ( MotionEvent event ) {
2017-07-24 20:24:16 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , "onDoubleTap" );
2017-04-17 21:42:01 -04:00
float normalizedX = event . getX ( 0 ) / mScreenSize . x ;
2017-01-26 16:46:24 -05:00
float normalizedY = event . getY ( 0 ) / mScreenSize . y ;
2017-04-17 21:42:01 -04:00
RTABMapLib . onTouchEvent ( 3 , event . getActionMasked (), normalizedX , normalizedY , 0 . 0f , 0 . 0f );
return true ;
}
2017-07-24 20:24:16 -04:00
@Override
2017-08-03 11:52:18 -04:00
public boolean onSingleTapConfirmed ( MotionEvent event ) {
if ( ! DISABLE_LOG ) Log . i ( TAG , "onSingleTapConfirmed" );
if ( mHudVisible )
{
notouchHandler . removeCallbacks ( notouchCallback );
notouchHandler . postDelayed ( notouchCallback , 0 );
}
else
{
resetNoTouchTimer ( true );
}
2017-07-24 20:24:16 -04:00
return true ;
}
2017-04-17 21:42:01 -04:00
}
2017-01-26 16:46:24 -05:00
@Override
public boolean onCreateOptionsMenu ( Menu menu ) {
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , "called onCreateOptionsMenu;" );
2017-01-26 16:46:24 -05:00
MenuInflater inflater = getMenuInflater ();
inflater . inflate ( R . menu . optionmenu , menu );
2017-02-05 17:24:45 -05:00
getActionBar (). setDisplayShowHomeEnabled ( true );
getActionBar (). setIcon ( R . drawable . ic_launcher );
2017-01-26 16:46:24 -05:00
mItemSave = menu . findItem ( R . id . save );
mItemOpen = menu . findItem ( R . id . open );
mItemPostProcessing = menu . findItem ( R . id . post_processing );
mItemExport = menu . findItem ( R . id . export );
mItemSettings = menu . findItem ( R . id . settings );
mItemModes = menu . findItem ( R . id . modes );
mItemReset = menu . findItem ( R . id . reset );
mItemLocalizationMode = menu . findItem ( R . id . localization_mode );
mItemTrajectoryMode = menu . findItem ( R . id . trajectory_mode );
mItemRenderingPointCloud = menu . findItem ( R . id . point_cloud );
mItemRenderingMesh = menu . findItem ( R . id . mesh );
mItemRenderingTextureMesh = menu . findItem ( R . id . texture_mesh );
mItemDataRecorderMode = menu . findItem ( R . id . data_recorder );
2017-02-22 09:48:45 -05:00
mItemStatusVisibility = menu . findItem ( R . id . status );
mItemDebugVisibility = menu . findItem ( R . id . debug );
2017-01-26 16:46:24 -05:00
mItemSave . setEnabled ( false );
mItemExport . setEnabled ( false );
mItemOpen . setEnabled ( false );
mItemPostProcessing . setEnabled ( false );
mItemDataRecorderMode . setEnabled ( false );
2017-02-05 17:24:45 -05:00
try
2017-01-26 16:46:24 -05:00
{
2017-02-05 17:24:45 -05:00
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
int renderingType = sharedPref . getInt ( getString ( R . string . pref_key_rendering ), Integer . parseInt ( getString ( R . string . pref_default_rendering )));
if ( renderingType == 0 )
{
mItemRenderingPointCloud . setChecked ( true );
}
else if ( renderingType == 1 )
{
mItemRenderingMesh . setChecked ( true );
}
else
{
mItemRenderingTextureMesh . setChecked ( true );
}
RTABMapLib . setMeshRendering (
mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked (),
mItemRenderingTextureMesh . isChecked ());
2017-02-15 19:07:10 -05:00
if ( mButtonBackfaceShown != null )
{
mButtonBackfaceShown . setVisibility ( mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked () ? View . VISIBLE : View . INVISIBLE );
}
2017-01-26 16:46:24 -05:00
}
2017-02-05 17:24:45 -05:00
catch ( Exception e )
2017-01-26 16:46:24 -05:00
{
2017-02-05 17:24:45 -05:00
Log . e ( TAG , "Error parsing rendering preferences: " + e . getMessage ());
mToast . makeText ( this , String . format ( "Error parsing rendering preferences: " + e . getMessage ()), mToast . LENGTH_LONG ). show ();
2017-01-26 16:46:24 -05:00
}
updateState ( mState );
return true ;
}
2017-02-05 17:24:45 -05:00
private long getFreeMemory ()
{
MemoryInfo mi = new MemoryInfo ();
ActivityManager activityManager = ( ActivityManager ) getSystemService ( ACTIVITY_SERVICE );
activityManager . getMemoryInfo ( mi );
return mi . availMem / 0x100000L ; // MB
}
2017-02-22 09:48:45 -05:00
private void updateStatusTexts ()
2016-09-08 11:55:44 -04:00
{
2017-02-22 09:48:45 -05:00
if ( mItemStatusVisibility != null && mItemDebugVisibility != null )
2017-01-26 16:46:24 -05:00
{
2017-06-21 17:14:40 -04:00
if (( mItemStatusVisibility . isChecked () || mState == State . STATE_VISUALIZING_WHILE_LOADING ) && mItemDebugVisibility . isChecked ())
2017-01-26 16:46:24 -05:00
{
2017-02-22 09:48:45 -05:00
mRenderer . updateTexts ( mStatusTexts );
}
2017-06-21 17:14:40 -04:00
else if (( mItemStatusVisibility . isChecked () || mState == State . STATE_VISUALIZING_WHILE_LOADING ))
2017-02-22 09:48:45 -05:00
{
mRenderer . updateTexts ( Arrays . copyOfRange ( mStatusTexts , 0 , 3 ));
}
else if ( mItemDebugVisibility . isChecked ())
{
mRenderer . updateTexts ( Arrays . copyOfRange ( mStatusTexts , 4 , mStatusTexts . length ));
2017-01-26 16:46:24 -05:00
}
else
{
2017-02-22 09:48:45 -05:00
mRenderer . updateTexts ( null );
}
}
}
private void updateStatsUI (
int processMemoryUsed ,
int loopClosureId ,
int inliers ,
int matches ,
int rejected ,
float optimizationMaxError ,
String [] statusTexts )
{
mStatusTexts = statusTexts ;
updateStatusTexts ();
if ( mButtonPause != null )
{
if ( ! mButtonPause . isChecked ())
{
//check if we are low in memory
long memoryUsed = processMemoryUsed ;
long memoryFree = getFreeMemory ();
2017-03-12 21:21:09 -04:00
if ( memoryFree < 200 )
2017-02-22 09:48:45 -05:00
{
mButtonPause . setChecked ( true );
pauseMapping ();
if ( mMemoryWarningDialog != null )
{
mMemoryWarningDialog . dismiss ();
mMemoryWarningDialog = null ;
}
mMemoryWarningDialog = new AlertDialog . Builder ( getActivity ())
. setTitle ( "Memory is full!" )
. setCancelable ( false )
. setMessage ( String . format ( "Scanning has been paused because free memory is too "
+ "low (%d MB). You should be able to save the database but some post-processing and exporting options may fail. "
+ "\n\nNote that for large environments, you can save multiple databases and "
+ "merge them with RTAB-Map Desktop version." , memoryUsed ))
. setPositiveButton ( "Ok" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
mMemoryWarningDialog = null ;
}
})
2017-02-28 21:50:50 -05:00
. setNeutralButton ( "Save" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
saveOnDevice ();
mMemoryWarningDialog = null ;
}
})
2017-02-22 09:48:45 -05:00
. create ();
mMemoryWarningDialog . show ();
}
else if ( mMemoryWarningDialog == null && memoryUsed * 3 > memoryFree && ( mItemDataRecorderMode == null || ! mItemDataRecorderMode . isChecked ()))
{
mMemoryWarningDialog = new AlertDialog . Builder ( getActivity ())
. setTitle ( "Warning: Memory is almost full!" )
. setCancelable ( false )
. setMessage ( String . format ( "Free memory (%d MB) should be at least 3 times the "
+ "memory used (%d MB) so that some post-processing and exporting options "
+ "have enough memory to work correctly. If you just want to save the database "
+ "after scanning, you can continue until the next warning.\n\n"
+ "Note that showing only point clouds reduces memory needed for rendering." , memoryFree , memoryUsed ))
. setPositiveButton ( "Pause" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
mButtonPause . setChecked ( true );
pauseMapping ();
}
})
. setNeutralButton ( "Continue" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
}
})
. create ();
mMemoryWarningDialog . show ();
}
2017-01-26 16:46:24 -05:00
}
}
2017-02-22 09:48:45 -05:00
2017-01-26 16:46:24 -05:00
if ( mButtonPause != null && ! mButtonPause . isChecked ())
{
if ( loopClosureId > 0 )
{
2017-02-15 19:07:10 -05:00
mToast . setText ( String . format ( "Loop closure detected! (%d/%d inliers)" , inliers , matches ));
2017-01-26 16:46:24 -05:00
mToast . show ();
}
2017-02-15 19:07:10 -05:00
else if ( rejected > 0 )
2017-01-26 16:46:24 -05:00
{
2017-02-15 19:07:10 -05:00
if ( inliers >= Integer . parseInt ( mMinInliers ))
{
2017-03-05 21:48:18 -05:00
if ( optimizationMaxError > 0 . 0f )
{
mToast . setText ( String . format ( "Loop closure rejected, too high graph optimization error (%.3fm > %sm)." , optimizationMaxError , mMaxOptimizationError ));
}
else
{
mToast . setText ( String . format ( "Loop closure rejected, graph optimization failed! You may try a different Graph Optimizer (see Mapping options)." ));
}
2017-02-15 19:07:10 -05:00
}
else
{
mToast . setText ( String . format ( "Loop closure rejected, not enough inliers (%d/%d < %s)." , inliers , matches , mMinInliers ));
}
2017-01-26 16:46:24 -05:00
mToast . show ();
}
}
2016-09-08 11:55:44 -04:00
}
2016-03-17 22:37:59 -04:00
2017-01-26 16:46:24 -05:00
// called from jni
public void updateStatsCallback (
final int nodes ,
final int words ,
final int points ,
final int polygons ,
final float updateTime ,
final int loopClosureId ,
final int highestHypId ,
2017-02-22 09:48:45 -05:00
final int processMemoryUsed ,
2017-01-26 16:46:24 -05:00
final int databaseMemoryUsed ,
final int inliers ,
2017-02-15 19:07:10 -05:00
final int matches ,
2017-02-22 09:48:45 -05:00
final int featuresExtracted ,
2017-01-26 16:46:24 -05:00
final float hypothesis ,
final int nodesDrawn ,
final float fps ,
2017-02-05 17:24:45 -05:00
final int rejected ,
2017-02-15 19:07:10 -05:00
final float rehearsalValue ,
final float optimizationMaxError )
2017-01-26 16:46:24 -05:00
{
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "updateStatsCallback()" ));
2016-03-17 22:37:59 -04:00
2017-02-22 09:48:45 -05:00
final String [] statusTexts = new String [ 16 ] ;
2017-03-12 21:21:09 -04:00
if ( mButtonPause != null && ! mButtonPause . isChecked ())
2017-02-22 09:48:45 -05:00
{
2017-03-12 21:21:09 -04:00
String updateValue = mUpdateRate . compareTo ( "0" ) == 0 ? "Max" : mUpdateRate ;
statusTexts [ 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 ));
2017-02-22 09:48:45 -05:00
}
else
{
2017-03-12 21:21:09 -04:00
statusTexts [ 0 ] = mStatusTexts [ 0 ] ;
2017-02-22 09:48:45 -05:00
}
// getNativeHeapAllocatedSize() is too slow, so we need to use the estimate.
// Multiply by 3/2 to match getNativeHeapAllocatedSize()
final int adjustedMemoryUsed = ( processMemoryUsed * 3 ) / 2 ;
2017-03-12 21:21:09 -04:00
if ( mButtonPause != null )
{
if ( ! mButtonPause . isChecked ())
{
statusTexts [ 1 ] = getString ( R . string . memory ) + adjustedMemoryUsed ;
}
else if ( mState == State . STATE_PROCESSING )
{
// This request is long to do, only do it when processing.
statusTexts [ 1 ] = getString ( R . string . memory ) + String . valueOf ( Debug . getNativeHeapAllocatedSize () / ( 1024 * 1024 ));
}
else
{
statusTexts [ 1 ] = mStatusTexts [ 1 ] ;
}
}
else
{
statusTexts [ 1 ] = mStatusTexts [ 1 ] ;
}
2017-02-22 09:48:45 -05:00
statusTexts [ 2 ] = getString ( R . string . free_memory ) + getFreeMemory ();
if ( loopClosureId > 0 )
{
++ mTotalLoopClosures ;
}
2017-03-12 21:21:09 -04:00
mMapNodes = nodes ;
2017-02-22 09:48:45 -05:00
int index = 4 ;
statusTexts [ index ++] = getString ( R . string . nodes ) + nodes + " (" + nodesDrawn + " shown)" ;
statusTexts [ index ++] = getString ( R . string . words ) + words ;
statusTexts [ index ++] = getString ( R . string . database_size ) + databaseMemoryUsed ;
statusTexts [ index ++] = getString ( R . string . points ) + points ;
statusTexts [ index ++] = getString ( R . string . polygons ) + polygons ;
statusTexts [ index ++] = getString ( R . string . update_time ) + ( int )( updateTime ) + " / " + ( mTimeThr . compareTo ( "0" ) == 0 ? "No Limit" : mTimeThr );
statusTexts [ index ++] = getString ( R . string . features ) + featuresExtracted + " / " + ( mMaxFeatures . compareTo ( "0" ) == 0 ? "No Limit" : mMaxFeatures . compareTo ( "-1" ) == 0 ? "Disabled" : mMaxFeatures );
statusTexts [ index ++] = getString ( R . string . rehearsal ) + ( int )( rehearsalValue * 100 . 0f );
statusTexts [ index ++] = getString ( R . string . total_loop ) + mTotalLoopClosures ;
statusTexts [ index ++] = getString ( R . string . inliers ) + inliers ;
statusTexts [ index ++] = getString ( R . string . hypothesis ) + ( int )( hypothesis * 100 . 0f ) + " / " + ( int )( Float . parseFloat ( mLoopThr ) * 100 . 0f ) + " (" + ( loopClosureId > 0 ? loopClosureId : highestHypId ) + ")" ;
statusTexts [ index ++] = getString ( R . string . fps ) + ( int ) fps + " Hz" ;
2017-01-26 16:46:24 -05:00
runOnUiThread ( new Runnable () {
2017-02-22 09:48:45 -05:00
public void run () {
updateStatsUI ( adjustedMemoryUsed , loopClosureId , inliers , matches , rejected , optimizationMaxError , statusTexts );
}
2016-02-15 19:35:24 -05:00
});
}
2017-01-26 16:46:24 -05:00
private void rtabmapInitEventUI (
int status ,
String msg )
{
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "rtabmapInitEventsUI() status=%d msg=%s" , status , msg ));
2017-01-26 16:46:24 -05:00
2017-06-21 17:14:40 -04:00
int optimizedMeshDetected = 0 ;
if ( msg . equals ( "Loading optimized cloud...done!" ))
{
optimizedMeshDetected = 1 ;
}
else if ( msg . equals ( "Loading optimized mesh...done!" ))
{
optimizedMeshDetected = 2 ;
}
else if ( msg . equals ( "Loading optimized texture mesh...done!" ))
{
optimizedMeshDetected = 3 ;
}
if ( optimizedMeshDetected > 0 )
{
resetNoTouchTimer ();
mSavedRenderingType = mItemRenderingPointCloud . isChecked () ? 0 : mItemRenderingMesh . isChecked () ? 1 : 2 ;
if ( optimizedMeshDetected == 1 )
{
mItemRenderingPointCloud . setChecked ( true );
}
else if ( optimizedMeshDetected == 2 )
{
mItemRenderingMesh . setChecked ( true );
}
else // isOBJ
{
mItemRenderingTextureMesh . setChecked ( true );
}
updateState ( State . STATE_VISUALIZING_WHILE_LOADING );
2017-06-28 13:59:20 -04:00
if ( mButtonCameraView . getSelectedItemPosition () == 0 )
2017-06-21 17:14:40 -04:00
{
2017-06-28 13:59:20 -04:00
setCamera ( 2 );
2017-06-21 17:14:40 -04:00
}
mToast . makeText ( getActivity (), String . format ( "Optimized mesh detected in the database, it is shown while the database is loading..." ), mToast . LENGTH_LONG ). show ();
mProgressDialog . dismiss ();
}
2017-01-26 16:46:24 -05:00
if ( mButtonPause != null )
{
if ( mButtonPause . isChecked ())
{
2017-02-22 09:48:45 -05:00
mStatusTexts [ 0 ] = getString ( R . string . status ) + ( status == 1 && msg . isEmpty () ? "Paused" : msg );
2017-01-26 16:46:24 -05:00
}
2017-03-12 21:21:09 -04:00
else if ( mItemLocalizationMode != null && mItemDataRecorderMode != null )
2017-01-26 16:46:24 -05:00
{
2017-03-12 21:21:09 -04:00
mStatusTexts [ 0 ] = getString ( R . string . status ) + ( status == 1 && msg . isEmpty () ? ( mItemDataRecorderMode != null && mItemDataRecorderMode . isChecked () ? "Recording" : mItemLocalizationMode != null && mItemLocalizationMode . isChecked () ? "Localization" : "Mapping" ): msg );
2017-01-26 16:46:24 -05:00
}
2017-02-22 09:48:45 -05:00
mStatusTexts [ 1 ] = getString ( R . string . memory ) + String . valueOf ( Debug . getNativeHeapAllocatedSize () / ( 1024 * 1024 ));
mStatusTexts [ 2 ] = getString ( R . string . free_memory ) + String . valueOf ( getFreeMemory ());
updateStatusTexts ();
2017-01-26 16:46:24 -05:00
}
}
//called from jni
public void rtabmapInitEventCallback (
final int status ,
final String msg )
{
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "rtabmapInitEventCallback()" ));
2017-01-26 16:46:24 -05:00
runOnUiThread ( new Runnable () {
public void run () {
rtabmapInitEventUI ( status , msg );
}
});
}
2017-02-28 21:50:50 -05:00
private void updateProgressionUI (
int count ,
int max )
{
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "updateProgressionUI() count=%d max=%s" , count , max ));
2017-02-28 21:50:50 -05:00
mExportProgressDialog . setMax ( max );
mExportProgressDialog . setProgress ( count );
}
//called from jni
public void updateProgressionCallback (
final int count ,
final int max )
{
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "updateProgressionCallback()" ));
2017-02-28 21:50:50 -05:00
runOnUiThread ( new Runnable () {
public void run () {
updateProgressionUI ( count , max );
}
});
}
2017-01-26 16:46:24 -05:00
private void tangoEventUI (
int type ,
String key ,
String value )
{
/**
*
* "TangoServiceException:X" - The service has encountered an exception, and a text description is given in X.
* "FisheyeOverExposed:X" - the fisheye image is over exposed with average pixel value X px.
* "FisheyeUnderExposed:X" - the fisheye image is under exposed with average pixel value X px.
* "ColorOverExposed:X" - the color image is over exposed with average pixel value X px.
* "ColorUnderExposed:X" - the color image is under exposed with average pixel value X px.
* "TooFewFeaturesTracked:X" - too few features were tracked in the fisheye image. The number of features tracked is X.
* "AreaDescriptionSaveProgress:X" - ADF saving is X * 100 percent complete.
* "Unknown"
*/
String str = null ;
if ( key . equals ( "TangoServiceException" ))
str = String . format ( "Tango service exception: %s" , value );
else if ( key . equals ( "FisheyeOverExposed" ))
; //str = String.format("The fisheye image is over exposed with average pixel value %s px.", value);
else if ( key . equals ( "FisheyeUnderExposed" ))
; //str = String.format("The fisheye image is under exposed with average pixel value %s px.", value);
else if ( key . equals ( "ColorOverExposed" ))
; //str = String.format("The color image is over exposed with average pixel value %s px.", value);
else if ( key . equals ( "ColorUnderExposed" ))
; //str = String.format("The color image is under exposed with average pixel value %s px.", value);
else if ( key . equals ( "CameraTango" ))
str = value ;
else if ( key . equals ( "TooFewFeaturesTracked" ))
{
if ( ! value . equals ( "0" ))
{
str = String . format ( "Too few features (%s) were tracked in the fisheye image. This may result in poor odometry!" , value );
}
}
else
{
str = String . format ( "Unknown Tango event detected!? (type=%d)" , type );
}
if ( str != null )
{
mToast . setText ( str );
mToast . show ();
}
}
//called from jni
public void tangoEventCallback (
final int type ,
final String key ,
final String value )
{
if ( mButtonPause != null && ! mButtonPause . isChecked ())
{
runOnUiThread ( new Runnable () {
public void run () {
tangoEventUI ( type , key , value );
}
2016-09-02 22:37:12 -04:00
});
2017-01-26 16:46:24 -05:00
}
}
private boolean CheckTangoCoreVersion ( int minVersion ) {
int versionNumber = 0 ;
String packageName = TANGO_PACKAGE_NAME ;
try {
PackageInfo pi = getApplicationContext (). getPackageManager (). getPackageInfo ( packageName ,
PackageManager . GET_META_DATA );
versionNumber = pi . versionCode ;
} catch ( NameNotFoundException e ) {
e . printStackTrace ();
}
return ( minVersion <= versionNumber );
}
private RTABMapActivity getActivity () { return this ;}
private void standardOptimization () {
2017-02-28 21:50:50 -05:00
mExportProgressDialog . setTitle ( "Post-Processing" );
mExportProgressDialog . setMessage ( String . format ( "Please wait while optimizing..." ));
mExportProgressDialog . setProgress ( 0 );
mExportProgressDialog . show ();
2017-01-26 16:46:24 -05:00
updateState ( State . STATE_PROCESSING );
Thread workingThread = new Thread ( new Runnable () {
public void run () {
final int loopDetected = RTABMapLib . postProcessing ( - 1 );
runOnUiThread ( new Runnable () {
public void run () {
2017-02-28 21:50:50 -05:00
if ( mExportProgressDialog . isShowing ())
2017-01-26 16:46:24 -05:00
{
2017-02-28 21:50:50 -05:00
mExportProgressDialog . dismiss ();
if ( loopDetected >= 0 )
{
mTotalLoopClosures += loopDetected ;
mProgressDialog . setTitle ( "Post-Processing" );
mProgressDialog . setMessage ( String . format ( "Optimization done! Increasing visual appeal..." ));
mProgressDialog . show ();
}
else if ( loopDetected < 0 )
{
mToast . makeText ( getActivity (), String . format ( "Optimization failed!" ), mToast . LENGTH_LONG ). show ();
}
2017-01-26 16:46:24 -05:00
}
2017-02-28 21:50:50 -05:00
else
2017-01-26 16:46:24 -05:00
{
2017-02-28 21:50:50 -05:00
mToast . makeText ( getActivity (), String . format ( "Optimization canceled" ), mToast . LENGTH_LONG ). show ();
2017-01-26 16:46:24 -05:00
}
updateState ( State . STATE_IDLE );
}
});
}
});
workingThread . start ();
}
2017-06-03 20:06:45 -04:00
private Handler notouchHandler = new Handler (){
public void handleMessage ( Message msg ) {
}
};
private Runnable notouchCallback = new Runnable () {
@Override
public void run () {
2017-06-21 20:54:16 -04:00
if ( ! mProgressDialog . isShowing () && ! mMenuOpened )
{
setNavVisibility ( false );
mHudVisible = false ;
updateState ( mState );
}
else
{
resetNoTouchTimer ();
}
2017-06-03 20:06:45 -04:00
}
};
public void resetNoTouchTimer (){
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( false );
}
public void resetNoTouchTimer ( boolean showHud ){
if ( showHud )
2017-06-03 20:06:45 -04:00
{
mHudVisible = true ;
2017-07-24 20:24:16 -04:00
setNavVisibility ( true );
if ( mItemSave != null )
{
updateState ( mState );
}
2017-06-03 20:06:45 -04:00
}
2017-07-24 20:24:16 -04:00
2017-06-03 20:06:45 -04:00
notouchHandler . removeCallbacks ( notouchCallback );
notouchHandler . postDelayed ( notouchCallback , NOTOUCH_TIMEOUT );
}
public void stopDisconnectTimer (){
notouchHandler . removeCallbacks ( notouchCallback );
}
2017-03-12 21:21:09 -04:00
2017-01-26 16:46:24 -05:00
private void updateState ( State state )
2017-02-15 19:07:10 -05:00
{
2017-03-12 21:21:09 -04:00
if ( mState == State . STATE_VISUALIZING && state == State . STATE_IDLE && mMapNodes > 100 )
{
mToast . makeText ( getActivity (), String . format ( "Re-adding %d online clouds, this may take some time..." , mMapNodes ), mToast . LENGTH_LONG ). show ();
}
2017-01-26 16:46:24 -05:00
mState = state ;
2017-07-24 20:24:16 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "updateState() state=%s hud=%d" , state . toString (), mHudVisible ? 1 : 0 ));
2017-01-26 16:46:24 -05:00
switch ( state )
{
case STATE_PROCESSING :
mButtonLighting . setVisibility ( View . INVISIBLE );
2017-06-12 19:08:51 -04:00
mButtonWireframe . setVisibility ( View . INVISIBLE );
2017-01-27 11:47:57 -05:00
mButtonCloseVisualization . setVisibility ( View . INVISIBLE );
2017-02-15 19:07:10 -05:00
mButtonSaveOnDevice . setVisibility ( View . INVISIBLE );
mButtonShareOnSketchfab . setVisibility ( View . INVISIBLE );
2017-01-26 16:46:24 -05:00
mItemSave . setEnabled ( false );
mItemExport . setEnabled ( false );
mItemOpen . setEnabled ( false );
mItemPostProcessing . setEnabled ( false );
mItemSettings . setEnabled ( false );
mItemReset . setEnabled ( false );
mItemModes . setEnabled ( false );
2017-02-15 19:07:10 -05:00
mButtonPause . setVisibility ( View . INVISIBLE );
2017-01-26 16:46:24 -05:00
break ;
case STATE_VISUALIZING :
2017-06-12 19:08:51 -04:00
mButtonLighting . setVisibility ( mHudVisible && ! mItemRenderingPointCloud . isChecked () ? View . VISIBLE : View . INVISIBLE );
mButtonWireframe . setVisibility ( mHudVisible && ! mItemRenderingPointCloud . isChecked () ? View . VISIBLE : View . INVISIBLE );
2017-06-03 20:06:45 -04:00
mButtonCloseVisualization . setVisibility ( mHudVisible ? View . VISIBLE : View . INVISIBLE );
2017-06-20 17:29:06 -04:00
mButtonCloseVisualization . setEnabled ( true );
2017-06-03 20:06:45 -04:00
mButtonSaveOnDevice . setVisibility ( mHudVisible ? View . VISIBLE : View . INVISIBLE );
mButtonShareOnSketchfab . setVisibility ( mHudVisible ? View . VISIBLE : View . INVISIBLE );
2017-01-26 16:46:24 -05:00
mItemSave . setEnabled ( mButtonPause . isChecked ());
mItemExport . setEnabled ( mButtonPause . isChecked () && ! mItemDataRecorderMode . isChecked ());
2017-03-04 19:34:40 -05:00
mItemOpen . setEnabled ( false );
mItemPostProcessing . setEnabled ( false );
2017-01-26 16:46:24 -05:00
mItemSettings . setEnabled ( true );
mItemReset . setEnabled ( true );
mItemModes . setEnabled ( true );
2017-02-15 19:07:10 -05:00
mButtonPause . setVisibility ( View . INVISIBLE );
2017-01-26 16:46:24 -05:00
mItemDataRecorderMode . setEnabled ( mButtonPause . isChecked ());
break ;
2017-06-20 17:29:06 -04:00
case STATE_VISUALIZING_WHILE_LOADING :
mButtonLighting . setVisibility ( mHudVisible && ! mItemRenderingPointCloud . isChecked () ? View . VISIBLE : View . INVISIBLE );
mButtonWireframe . setVisibility ( mHudVisible && ! mItemRenderingPointCloud . isChecked () ? View . VISIBLE : View . INVISIBLE );
mButtonCloseVisualization . setVisibility ( mHudVisible ? View . VISIBLE : View . INVISIBLE );
mButtonCloseVisualization . setEnabled ( false );
mButtonSaveOnDevice . setVisibility ( View . INVISIBLE );
mButtonShareOnSketchfab . setVisibility ( View . INVISIBLE );
mItemSave . setEnabled ( false );
mItemExport . setEnabled ( false );
mItemOpen . setEnabled ( false );
mItemPostProcessing . setEnabled ( false );
mItemSettings . setEnabled ( false );
mItemReset . setEnabled ( false );
mItemModes . setEnabled ( false );
mButtonPause . setVisibility ( View . INVISIBLE );
break ;
2017-01-26 16:46:24 -05:00
default :
mButtonLighting . setVisibility ( View . INVISIBLE );
2017-06-12 19:08:51 -04:00
mButtonWireframe . setVisibility ( View . INVISIBLE );
2017-01-27 11:47:57 -05:00
mButtonCloseVisualization . setVisibility ( View . INVISIBLE );
2017-02-15 19:07:10 -05:00
mButtonSaveOnDevice . setVisibility ( View . INVISIBLE );
mButtonShareOnSketchfab . setVisibility ( View . INVISIBLE );
2017-01-26 16:46:24 -05:00
mItemSave . setEnabled ( mButtonPause . isChecked ());
mItemExport . setEnabled ( mButtonPause . isChecked () && ! mItemDataRecorderMode . isChecked ());
mItemOpen . setEnabled ( mButtonPause . isChecked () && ! mItemDataRecorderMode . isChecked ());
mItemPostProcessing . setEnabled ( mButtonPause . isChecked () && ! mItemDataRecorderMode . isChecked ());
mItemSettings . setEnabled ( true );
mItemReset . setEnabled ( true );
mItemModes . setEnabled ( true );
2017-06-03 20:06:45 -04:00
mButtonPause . setVisibility ( mHudVisible ? View . VISIBLE : View . INVISIBLE );
2017-01-27 11:47:57 -05:00
mItemDataRecorderMode . setEnabled ( mButtonPause . isChecked ());
2017-01-26 16:46:24 -05:00
break ;
}
2017-06-28 13:59:20 -04:00
mButtonCameraView . setVisibility ( mHudVisible ? View . VISIBLE : View . INVISIBLE );
2017-06-03 20:06:45 -04:00
mButtonBackfaceShown . setVisibility ( mHudVisible && ( mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked ()) ? View . VISIBLE : View . INVISIBLE );
2017-08-03 11:52:18 -04:00
mSeekBarOrthoCut . setVisibility ( mHudVisible && mButtonCameraView . getSelectedItemPosition () == 3 ? View . VISIBLE : View . INVISIBLE );
2017-06-28 13:59:20 -04:00
mSeekBarGrid . setVisibility ( mHudVisible && mSeekBarGrid . isEnabled () && mButtonCameraView . getSelectedItemPosition () == 3 ? View . VISIBLE : View . INVISIBLE );
2017-01-26 16:46:24 -05:00
}
private void pauseMapping () {
updateState ( State . STATE_IDLE );
if ( mButtonPause . isChecked ())
{
RTABMapLib . setPausedMapping ( true );
2017-02-22 09:48:45 -05:00
mStatusTexts [ 0 ] = getString ( R . string . status ) + "Paused" ;
mStatusTexts [ 1 ] = getString ( R . string . memory ) + String . valueOf ( Debug . getNativeHeapAllocatedSize () / ( 1024 * 1024 ));
mStatusTexts [ 2 ] = getString ( R . string . free_memory ) + String . valueOf ( getFreeMemory ());
updateStatusTexts ();
2017-01-26 16:46:24 -05:00
mMapIsEmpty = false ;
2017-02-15 19:07:10 -05:00
mDateOnPause = new Date ();
2017-01-26 16:46:24 -05:00
2017-02-22 09:48:45 -05:00
long memoryFree = getFreeMemory ();
2017-06-21 17:14:40 -04:00
if ( ! mOnPause && ! mItemLocalizationMode . isChecked () && ! mItemDataRecorderMode . isChecked () && memoryFree >= 100 && mMapNodes > 2 )
2017-01-26 16:46:24 -05:00
{
// Do standard post processing?
new AlertDialog . Builder ( getActivity ())
. setTitle ( "Mapping Paused! Optimize Now?" )
. setMessage ( "Do you want to do standard map optimization now? This can be also done later using \"Optimize\" menu." )
. setPositiveButton ( "Yes" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
standardOptimization ();
}
})
. setNegativeButton ( "No" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
// do nothing...
}
})
. show ();
}
}
else
{
2017-02-22 09:48:45 -05:00
if ( mMemoryWarningDialog != null )
{
mMemoryWarningDialog . dismiss ();
mMemoryWarningDialog = null ;
}
2017-01-26 16:46:24 -05:00
RTABMapLib . setPausedMapping ( false );
2017-02-22 09:48:45 -05:00
2017-01-26 16:46:24 -05:00
if ( mItemDataRecorderMode . isChecked ())
{
mToast . makeText ( getActivity (), String . format ( "Data Recorder Mode: no map is created, only raw data is recorded." ), mToast . LENGTH_LONG ). show ();
}
else if ( ! mMapIsEmpty )
{
mToast . makeText ( getActivity (), String . format ( "On resume, a new map is created. Tip: Try relocalizing in the previous area." ), mToast . LENGTH_LONG ). show ();
}
}
}
public boolean onOptionsItemSelected ( MenuItem item ) {
2017-06-20 17:29:06 -04:00
resetNoTouchTimer ();
2017-03-12 21:21:09 -04:00
if ( ! DISABLE_LOG ) Log . i ( TAG , "called onOptionsItemSelected; selected item: " + item );
2017-01-26 16:46:24 -05:00
int itemId = item . getItemId ();
if ( itemId == R . id . post_processing_standard )
{
standardOptimization ();
}
else if ( itemId == R . id . detect_more_loop_closures )
{
2016-04-04 13:03:43 -04:00
mProgressDialog . setTitle ( "Post-Processing" );
mProgressDialog . setMessage ( String . format ( "Please wait while detecting more loop closures..." ));
mProgressDialog . show ();
2017-01-26 16:46:24 -05:00
updateState ( State . STATE_PROCESSING );
2016-04-04 13:03:43 -04:00
Thread workingThread = new Thread ( new Runnable () {
2017-01-26 16:46:24 -05:00
public void run () {
final int loopDetected = RTABMapLib . postProcessing ( 2 );
runOnUiThread ( new Runnable () {
public void run () {
mProgressDialog . dismiss ();
if ( loopDetected >= 0 )
{
mTotalLoopClosures += loopDetected ;
mToast . makeText ( getActivity (), String . format ( "Detection done! %d new loop closure(s) added." , loopDetected ), mToast . LENGTH_SHORT ). show ();
}
else if ( loopDetected < 0 )
{
mToast . makeText ( getActivity (), String . format ( "Detection failed!" ), mToast . LENGTH_SHORT ). show ();
}
updateState ( State . STATE_IDLE );
}
});
}
2016-04-04 13:03:43 -04:00
});
workingThread . start ();
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . global_graph_optimization )
{
2016-04-04 13:03:43 -04:00
mProgressDialog . setTitle ( "Post-Processing" );
mProgressDialog . setMessage ( String . format ( "Global graph optimization..." ));
mProgressDialog . show ();
2017-01-26 16:46:24 -05:00
updateState ( State . STATE_PROCESSING );
2016-04-04 13:03:43 -04:00
Thread workingThread = new Thread ( new Runnable () {
2017-01-26 16:46:24 -05:00
public void run () {
final int value = RTABMapLib . postProcessing ( 0 );
runOnUiThread ( new Runnable () {
public void run () {
mProgressDialog . dismiss ();
if ( value >= 0 )
{
mToast . makeText ( getActivity (), String . format ( "Optimization done!" ), mToast . LENGTH_SHORT ). show ();
}
else if ( value < 0 )
{
mToast . makeText ( getActivity (), String . format ( "Optimization failed!" ), mToast . LENGTH_SHORT ). show ();
}
updateState ( State . STATE_IDLE );
}
});
}
2016-04-04 13:03:43 -04:00
});
workingThread . start ();
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . polygons_filtering )
{
mProgressDialog . setTitle ( "Post-Processing" );
mProgressDialog . setMessage ( String . format ( "Noise filtering..." ));
mProgressDialog . show ();
RTABMapLib . postProcessing ( 4 );
}
else if ( itemId == R . id . gain_compensation_fast )
{
mProgressDialog . setTitle ( "Post-Processing" );
2017-04-01 14:14:36 -04:00
mProgressDialog . setMessage ( String . format ( "Adjusting Colors (Fast)..." ));
2017-01-26 16:46:24 -05:00
mProgressDialog . show ();
RTABMapLib . postProcessing ( 5 );
}
else if ( itemId == R . id . gain_compensation_full )
{
mProgressDialog . setTitle ( "Post-Processing" );
2017-04-01 14:14:36 -04:00
mProgressDialog . setMessage ( String . format ( "Adjusting Colors (Full)..." ));
2017-01-26 16:46:24 -05:00
mProgressDialog . show ();
RTABMapLib . postProcessing ( 6 );
}
else if ( itemId == R . id . bilateral_filtering )
{
mProgressDialog . setTitle ( "Post-Processing" );
mProgressDialog . setMessage ( String . format ( "Mesh smoothing..." ));
mProgressDialog . show ();
RTABMapLib . postProcessing ( 7 );
}
else if ( itemId == R . id . sba )
{
2016-04-04 13:03:43 -04:00
mProgressDialog . setTitle ( "Post-Processing" );
mProgressDialog . setMessage ( String . format ( "Bundle adjustement..." ));
mProgressDialog . show ();
2017-01-26 16:46:24 -05:00
2016-04-04 13:03:43 -04:00
Thread workingThread = new Thread ( new Runnable () {
2017-01-26 16:46:24 -05:00
public void run () {
final int value = RTABMapLib . postProcessing ( 1 );
runOnUiThread ( new Runnable () {
public void run () {
mProgressDialog . dismiss ();
if ( value >= 0 )
{
mToast . makeText ( getActivity (), String . format ( "Optimization done!" ), mToast . LENGTH_SHORT ). show ();
}
else if ( value < 0 )
{
mToast . makeText ( getActivity (), String . format ( "Optimization failed!" ), mToast . LENGTH_SHORT ). show ();
}
}
});
}
2016-04-04 13:03:43 -04:00
});
workingThread . start ();
2017-01-26 16:46:24 -05:00
}
2017-02-22 09:48:45 -05:00
else if ( itemId == R . id . status )
{
item . setChecked ( ! item . isChecked ());
updateStatusTexts ();
}
2017-01-26 16:46:24 -05:00
else if ( itemId == R . id . debug )
{
item . setChecked ( ! item . isChecked ());
2017-02-22 09:48:45 -05:00
updateStatusTexts ();
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . mesh || itemId == R . id . texture_mesh || itemId == R . id . point_cloud )
{
item . setChecked ( true );
RTABMapLib . setMeshRendering (
mItemRenderingMesh . isChecked () || mItemRenderingTextureMesh . isChecked (),
mItemRenderingTextureMesh . isChecked ());
2017-02-15 19:07:10 -05:00
2017-06-12 19:08:51 -04:00
resetNoTouchTimer ();
if ( mState != State . STATE_VISUALIZING )
{
// save preference
int type = mItemRenderingPointCloud . isChecked () ? 0 : mItemRenderingMesh . isChecked () ? 1 : 2 ;
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
SharedPreferences . Editor editor = sharedPref . edit ();
editor . putInt ( getString ( R . string . pref_key_rendering ), type );
// Commit the edits!
editor . commit ();
}
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . map_shown )
{
item . setChecked ( ! item . isChecked ());
RTABMapLib . setMapCloudShown ( item . isChecked ());
}
else if ( itemId == R . id . odom_shown )
{
item . setChecked ( ! item . isChecked ());
RTABMapLib . setOdomCloudShown ( item . isChecked ());
}
else if ( itemId == R . id . localization_mode )
{
item . setChecked ( ! item . isChecked ());
RTABMapLib . setLocalizationMode ( item . isChecked ());
}
else if ( itemId == R . id . trajectory_mode )
{
item . setChecked ( ! item . isChecked ());
RTABMapLib . setTrajectoryMode ( item . isChecked ());
2017-01-30 12:29:34 -05:00
setCamera ( item . isChecked () ? 2 : 1 );
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . graph_optimization )
{
item . setChecked ( ! item . isChecked ());
RTABMapLib . setGraphOptimization ( item . isChecked ());
}
else if ( itemId == R . id . graph_visible )
{
item . setChecked ( ! item . isChecked ());
RTABMapLib . setGraphVisible ( item . isChecked ());
}
else if ( itemId == R . id . grid_visible )
{
item . setChecked ( ! item . isChecked ());
2017-06-28 13:59:20 -04:00
mSeekBarGrid . setEnabled ( item . isChecked ());
mSeekBarGrid . setVisibility ( mHudVisible && mSeekBarGrid . isEnabled () && mButtonCameraView . getSelectedItemPosition () == 3 ? View . VISIBLE : View . INVISIBLE );
2017-01-26 16:46:24 -05:00
RTABMapLib . setGridVisible ( item . isChecked ());
}
else if ( itemId == R . id . save )
{
AlertDialog . Builder builder = new AlertDialog . Builder ( this );
builder . setTitle ( "RTAB-Map Database Name (*.db):" );
final EditText input = new EditText ( this );
input . setInputType ( InputType . TYPE_CLASS_TEXT );
if ( mOpenedDatabasePath . isEmpty ())
{
2017-02-15 19:07:10 -05:00
String timeStamp = new SimpleDateFormat ( "yyMMdd-HHmmss" ). format ( mDateOnPause );
2017-01-26 16:46:24 -05:00
input . setText ( timeStamp );
}
else
{
File f = new File ( mOpenedDatabasePath );
String name = f . getName ();
input . setText ( name . substring ( 0 , name . lastIndexOf ( "." )));
}
2017-02-15 19:07:10 -05:00
input . setImeOptions ( EditorInfo . IME_FLAG_NO_EXTRACT_UI );
2017-01-26 16:46:24 -05:00
input . setSelectAllOnFocus ( true );
input . selectAll ();
builder . setView ( input );
builder . setPositiveButton ( "OK" , new DialogInterface . OnClickListener () {
@Override
public void onClick ( DialogInterface dialog , int which )
{
final String fileName = input . getText (). toString ();
dialog . dismiss ();
if ( ! fileName . isEmpty ())
{
File newFile = new File ( mWorkingDirectory + fileName + ".db" );
if ( newFile . exists ())
{
new AlertDialog . Builder ( getActivity ())
. setTitle ( "File Already Exists" )
. setMessage ( "Do you want to overwrite the existing file?" )
. setPositiveButton ( "Yes" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
2017-02-22 09:48:45 -05:00
saveDatabase ( fileName );
2016-11-21 17:09:04 -05:00
}
2017-01-26 16:46:24 -05:00
})
. setNegativeButton ( "No" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
dialog . dismiss ();
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-01-26 16:46:24 -05:00
}
})
. show ();
}
else
{
2017-02-22 09:48:45 -05:00
saveDatabase ( fileName );
2017-01-26 16:46:24 -05:00
}
}
}
});
2017-02-15 19:07:10 -05:00
AlertDialog alertToShow = builder . create ();
alertToShow . getWindow (). setSoftInputMode ( WindowManager . LayoutParams . SOFT_INPUT_STATE_VISIBLE );
alertToShow . show ();
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . reset )
{
mTotalLoopClosures = 0 ;
2017-02-22 09:48:45 -05:00
int index = 4 ;
2017-03-12 21:21:09 -04:00
mMapNodes = 0 ;
2017-02-22 09:48:45 -05:00
mStatusTexts [ index ++] = getString ( R . string . nodes ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . words ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . database_size ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . points ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . polygons ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . update_time ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . features ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . rehearsal ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . total_loop ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . inliers ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . hypothesis ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . fps ) + 0 ;
updateStatusTexts ();
2016-11-21 17:09:04 -05:00
2017-02-05 17:24:45 -05:00
mOpenedDatabasePath = "" ;
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
boolean databaseInMemory = sharedPref . getBoolean ( getString ( R . string . pref_key_db_in_memory ), Boolean . parseBoolean ( getString ( R . string . pref_default_db_in_memory )));
String tmpDatabase = mWorkingDirectory + RTABMAP_TMP_DB ;
( new File ( tmpDatabase )). delete ();
RTABMapLib . openDatabase ( tmpDatabase , databaseInMemory , false );
2017-01-26 16:46:24 -05:00
mMapIsEmpty = true ;
mItemSave . setEnabled ( false );
mItemExport . setEnabled ( false );
mItemPostProcessing . setEnabled ( false );
2017-02-05 17:24:45 -05:00
updateState ( State . STATE_IDLE );
2017-01-26 16:46:24 -05:00
}
else if ( itemId == R . id . data_recorder )
{
final boolean dataRecorderOldState = item . isChecked ();
new AlertDialog . Builder ( getActivity ())
. setTitle ( "Data Recorder Mode" )
. setMessage ( "Changing from/to data recorder mode will close the current session. Do you want to continue?" )
. setPositiveButton ( "Yes" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
// reset
mTotalLoopClosures = 0 ;
2017-02-22 09:48:45 -05:00
int index = 4 ;
2017-03-12 21:21:09 -04:00
mMapNodes = 0 ;
2017-02-22 09:48:45 -05:00
mStatusTexts [ index ++] = getString ( R . string . nodes ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . words ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . database_size ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . points ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . polygons ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . update_time ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . features ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . rehearsal ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . total_loop ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . inliers ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . hypothesis ) + 0 ;
mStatusTexts [ index ++] = getString ( R . string . fps ) + 0 ;
updateStatusTexts ();
2016-02-15 19:35:24 -05:00
2017-01-26 16:46:24 -05:00
mItemDataRecorderMode . setChecked ( ! dataRecorderOldState );
RTABMapLib . setDataRecorderMode ( mItemDataRecorderMode . isChecked ());
mOpenedDatabasePath = "" ;
2017-02-05 17:24:45 -05:00
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( getActivity ());
boolean databaseInMemory = sharedPref . getBoolean ( getString ( R . string . pref_key_db_in_memory ), Boolean . parseBoolean ( getString ( R . string . pref_default_db_in_memory )));
String tmpDatabase = mWorkingDirectory + RTABMAP_TMP_DB ;
( new File ( tmpDatabase )). delete ();
RTABMapLib . openDatabase ( tmpDatabase , databaseInMemory , false );
2017-01-26 16:46:24 -05:00
mItemOpen . setEnabled ( ! mItemDataRecorderMode . isChecked () && mButtonPause . isChecked ());
mItemPostProcessing . setEnabled ( ! mItemDataRecorderMode . isChecked () && mButtonPause . isChecked ());
mItemExport . setEnabled ( ! mItemDataRecorderMode . isChecked () && mButtonPause . isChecked ());
mItemLocalizationMode . setEnabled ( ! mItemDataRecorderMode . isChecked ());
if ( mItemDataRecorderMode . isChecked ())
{
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 ();
}
else
{
mToast . makeText ( getActivity (), String . format ( "Data recorder mode deactivated!" ), mToast . LENGTH_LONG ). show ();
}
}
})
. setNegativeButton ( "No" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
dialog . dismiss ();
}
})
. show ();
}
2017-02-22 09:48:45 -05:00
else if ( itemId == R . id . export_point_cloud ||
2017-04-17 21:42:01 -04:00
itemId == R . id . export_point_cloud_highrez )
2017-01-26 16:46:24 -05:00
{
2017-02-22 09:48:45 -05:00
final boolean regenerateCloud = itemId == R . id . export_point_cloud_highrez ;
2017-01-26 16:46:24 -05:00
2017-04-17 21:42:01 -04:00
export ( false , false , regenerateCloud , false , 0 );
2017-02-28 21:50:50 -05:00
}
else if ( itemId == R . id . export_optimized_mesh ||
itemId == R . id . export_optimized_mesh_texture )
{
final boolean isOBJ = itemId == R . id . export_optimized_mesh_texture ;
2017-02-15 19:07:10 -05:00
2017-02-28 21:50:50 -05:00
RelativeLayout linearLayout = new RelativeLayout ( this );
final NumberPicker aNumberPicker = new NumberPicker ( this );
aNumberPicker . setMaxValue ( 9 );
aNumberPicker . setMinValue ( 0 );
aNumberPicker . setWrapSelectorWheel ( false );
aNumberPicker . setDescendantFocusability ( NumberPicker . FOCUS_BLOCK_DESCENDANTS );
aNumberPicker . setFormatter ( new NumberPicker . Formatter () {
@Override
public String format ( int i ) {
if ( i == 0 )
{
return "No Limit" ;
}
return String . format ( "%d00 000" , i );
}
});
2017-03-14 10:54:23 -04:00
aNumberPicker . setValue ( 2 );
2017-01-26 16:46:24 -05:00
2017-02-28 21:50:50 -05:00
// Fix to correctly show value on first render
try {
Method method = aNumberPicker . getClass (). getDeclaredMethod ( "changeValueByOne" , boolean . class );
method . setAccessible ( true );
method . invoke ( aNumberPicker , true );
} catch ( NoSuchMethodException e ) {
e . printStackTrace ();
} catch ( IllegalArgumentException e ) {
e . printStackTrace ();
} catch ( IllegalAccessException e ) {
e . printStackTrace ();
} catch ( InvocationTargetException e ) {
e . printStackTrace ();
}
RelativeLayout . LayoutParams params = new RelativeLayout . LayoutParams ( 50 , 50 );
RelativeLayout . LayoutParams numPicerParams = new RelativeLayout . LayoutParams ( RelativeLayout . LayoutParams . WRAP_CONTENT , RelativeLayout . LayoutParams . WRAP_CONTENT );
numPicerParams . addRule ( RelativeLayout . CENTER_HORIZONTAL );
linearLayout . setLayoutParams ( params );
linearLayout . addView ( aNumberPicker , numPicerParams );
AlertDialog . Builder alertDialogBuilder = new AlertDialog . Builder ( this );
alertDialogBuilder . setTitle ( "Maximum polygons" );
alertDialogBuilder . setView ( linearLayout );
alertDialogBuilder
. setCancelable ( false )
. setPositiveButton ( "Ok" ,
new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog ,
int id ) {
export ( isOBJ , true , false , true , aNumberPicker . getValue () * 100000 );
}
})
. setNegativeButton ( "Cancel" ,
new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog ,
int id ) {
dialog . cancel ();
}
});
AlertDialog alertDialog = alertDialogBuilder . create ();
alertDialog . show ();
}
else if ( itemId == R . id . open )
{
2017-06-16 16:24:38 -04:00
final String [] files = Util . loadFileList ( mWorkingDirectory , true );
2017-02-28 21:50:50 -05:00
if ( files . length > 0 )
{
String [] filesWithSize = new String [ files . length ] ;
for ( int i = 0 ; i < filesWithSize . length ; ++ i )
{
File filePath = new File ( mWorkingDirectory + files [ i ] );
long mb = filePath . length () / ( 1024 * 1024 );
filesWithSize [ i ] = files [ i ] + " (" + mb + " MB)" ;
}
2017-06-20 17:29:06 -04:00
ArrayList < HashMap < String , String > > arrayList = new ArrayList < HashMap < String , String > > ();
for ( int i = 0 ; i < filesWithSize . length ; i ++ ) {
HashMap < String , String > hashMap = new HashMap < String , String > (); //create a hashmap to store the data in key value pair
hashMap . put ( "name" , filesWithSize [ i ] );
hashMap . put ( "path" , mWorkingDirectory + files [ i ] );
arrayList . add ( hashMap ); //add the hashmap into arrayList
}
String [] from = { "name" , "path" }; //string array
int [] to = { R . id . textView , R . id . imageView }; //int array of views id's
DatabaseListArrayAdapter simpleAdapter = new DatabaseListArrayAdapter ( this , arrayList , R . layout . database_list , from , to ); //Create object and set the parameters for simpleAdapter
2017-02-28 21:50:50 -05:00
AlertDialog . Builder builder = new AlertDialog . Builder ( this );
builder . setTitle ( "Choose Your File (*.db)" );
2017-06-20 17:29:06 -04:00
builder . setAdapter ( simpleAdapter , new DialogInterface . OnClickListener () {
//builder.setItems(filesWithSize, new DialogInterface.OnClickListener() {
2017-02-28 21:50:50 -05:00
public void onClick ( DialogInterface dialog , final int which ) {
// Adjust color now?
new AlertDialog . Builder ( getActivity ())
. setTitle ( "Opening database..." )
. setMessage ( "Do you want to adjust colors now?\nThis can be done later under Optimize menu." )
. setPositiveButton ( "Yes" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int whichIn ) {
openDatabase ( files [ which ] , true );
}
})
. setNeutralButton ( "No" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int whichIn ) {
openDatabase ( files [ which ] , false );
}
})
. show ();
return ;
}
});
builder . show ();
}
}
else if ( itemId == R . id . settings )
{
Intent intent = new Intent ( getActivity (), SettingsActivity . class );
startActivity ( intent );
mBlockBack = true ;
}
else if ( itemId == R . id . about )
{
AboutDialog about = new AboutDialog ( this );
about . setTitle ( "About RTAB-Map" );
about . show ();
}
return true ;
}
private void export ( final boolean isOBJ , final boolean meshing , final boolean regenerateCloud , final boolean optimized , final int optimizedMaxPolygons )
{
final String extension = isOBJ ? ".obj" : ".ply" ;
// get Export settings
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( this );
final String cloudVoxelSizeStr = sharedPref . getString ( getString ( R . string . pref_key_cloud_voxel ), getString ( R . string . pref_default_cloud_voxel ));
final float cloudVoxelSize = Float . parseFloat ( cloudVoxelSizeStr );
final int textureSize = isOBJ ? Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_texture_size ), getString ( R . string . pref_default_texture_size ))): 0 ;
2017-06-10 21:45:51 -04:00
final int textureCount = Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_texture_count ), getString ( R . string . pref_default_texture_count )));
2017-02-28 21:50:50 -05:00
final int normalK = Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_normal_k ), getString ( R . string . pref_default_normal_k )));
final float maxTextureDistance = Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_max_texture_distance ), getString ( R . string . pref_default_max_texture_distance )));
2017-03-04 19:34:40 -05:00
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 )));
2017-02-28 21:50:50 -05:00
final float optimizedVoxelSize = cloudVoxelSize ;
final int optimizedDepth = Integer . parseInt ( sharedPref . getString ( getString ( R . string . pref_key_opt_depth ), getString ( R . string . pref_default_opt_depth )));
final float optimizedColorRadius = Float . parseFloat ( sharedPref . getString ( getString ( R . string . pref_key_opt_color_radius ), getString ( R . string . pref_default_opt_color_radius )));
final boolean optimizedCleanWhitePolygons = sharedPref . getBoolean ( getString ( R . string . pref_key_opt_clean_white ), Boolean . parseBoolean ( getString ( R . string . pref_default_opt_clean_white )));
2017-07-24 20:24:16 -04:00
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 )));
2017-02-28 21:50:50 -05:00
final boolean blockRendering = sharedPref . getBoolean ( getString ( R . string . pref_key_block_render ), Boolean . parseBoolean ( getString ( R . string . pref_default_block_render )));
mExportProgressDialog . setTitle ( "Exporting" );
mExportProgressDialog . setMessage ( String . format ( "Please wait while preparing data to export..." ));
mExportProgressDialog . setProgress ( 0 );
final State previousState = mState ;
mExportProgressDialog . show ();
updateState ( State . STATE_PROCESSING );
2017-06-21 17:14:40 -04:00
2017-02-28 21:50:50 -05:00
Thread exportThread = new Thread ( new Runnable () {
public void run () {
2017-03-12 21:21:09 -04:00
final long startTime = System . currentTimeMillis () / 1000 ;
2017-02-28 21:50:50 -05:00
final boolean success = RTABMapLib . exportMesh (
cloudVoxelSize ,
regenerateCloud ,
meshing ,
textureSize ,
2017-06-10 21:45:51 -04:00
textureCount ,
2017-02-28 21:50:50 -05:00
normalK ,
optimized ,
optimizedVoxelSize ,
optimizedDepth ,
optimizedMaxPolygons ,
optimizedColorRadius ,
optimizedCleanWhitePolygons ,
2017-07-24 20:24:16 -04:00
optimizedMinClusterSize ,
2017-03-04 19:34:40 -05:00
maxTextureDistance ,
minTextureClusterSize ,
2017-02-28 21:50:50 -05:00
blockRendering );
runOnUiThread ( new Runnable () {
public void run () {
if ( mExportProgressDialog . isShowing ())
2017-07-24 20:24:16 -04:00
{
2017-02-15 19:07:10 -05:00
if ( success )
2017-07-24 20:24:16 -04:00
{
2017-02-22 09:48:45 -05:00
if ( ! meshing && cloudVoxelSize > 0 . 0f )
{
mToast . makeText ( getActivity (), String . format ( "Cloud assembled and voxelized at %s m." , cloudVoxelSizeStr ), mToast . LENGTH_LONG ). show ();
}
2017-03-12 21:21:09 -04:00
final long endTime = System . currentTimeMillis () / 1000 ;
2017-07-24 20:24:16 -04:00
if ( endTime - startTime > 10 )
{
// build notification
// the addAction re-use the same intent to keep the example short
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( getActivity ());
boolean notifySound = sharedPref . getBoolean ( getString ( R . string . pref_key_notification_sound ), Boolean . parseBoolean ( getString ( R . string . pref_default_notification_sound )));
Notification n = new Notification . Builder ( getActivity ())
. setContentTitle ( getString ( R . string . app_name ))
. setContentText ( "Data generated and ready to be exported!" )
. setSmallIcon ( R . drawable . ic_launcher )
. setDefaults ( notifySound ? Notification . DEFAULT_SOUND : 0 )
. setAutoCancel ( true ). build ();
NotificationManager notificationManager =
( NotificationManager ) getSystemService ( NOTIFICATION_SERVICE );
notificationManager . notify ( 0 , n );
}
2017-02-27 16:53:05 -05:00
2017-02-15 19:07:10 -05:00
// Visualize the result?
2017-02-27 16:53:05 -05:00
AlertDialog d = new AlertDialog . Builder ( getActivity ())
2017-02-15 19:07:10 -05:00
. setCancelable ( false )
2017-03-12 21:21:09 -04:00
. setTitle ( "Export Successful! (" + ( endTime - startTime ) + " sec)" )
2017-02-27 16:53:05 -05:00
. setMessage ( Html . fromHtml ( "Do you want visualize the result before saving to file or sharing to <a href=\"https://sketchfab.com/about\">Sketchfab</a>?" ))
2017-02-15 19:07:10 -05:00
. setPositiveButton ( "Yes" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-06-20 17:29:06 -04:00
mSavedRenderingType = mItemRenderingPointCloud . isChecked () ? 0 : mItemRenderingMesh . isChecked () ? 1 : 2 ;
2017-06-12 19:08:51 -04:00
if ( ! meshing )
{
mItemRenderingPointCloud . setChecked ( true );
}
else if ( ! isOBJ )
{
mItemRenderingMesh . setChecked ( true );
}
else // isOBJ
{
mItemRenderingTextureMesh . setChecked ( true );
}
2017-06-16 14:44:48 -04:00
if ( ! optimizedCleanWhitePolygons )
{
mButtonLighting . setChecked ( true );
RTABMapLib . setLighting ( true );
}
2017-02-15 19:07:10 -05:00
updateState ( State . STATE_VISUALIZING );
RTABMapLib . postExportation ( true );
2017-06-28 13:59:20 -04:00
if ( mButtonCameraView . getSelectedItemPosition () == 0 )
2017-02-15 19:07:10 -05:00
{
setCamera ( 2 );
2017-01-26 16:46:24 -05:00
}
2017-02-15 19:07:10 -05:00
}
})
. setNegativeButton ( "No" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
updateState ( State . STATE_IDLE );
RTABMapLib . postExportation ( false );
2017-02-27 16:53:05 -05:00
AlertDialog d2 = new AlertDialog . Builder ( getActivity ())
2017-02-15 19:07:10 -05:00
. setCancelable ( false )
. setTitle ( "Save to..." )
2017-02-27 16:53:05 -05:00
. setMessage ( Html . fromHtml ( "Do you want to share to <a href=\"https://sketchfab.com/about\">Sketchfab</a> or save it on device?" ))
2017-02-15 19:07:10 -05:00
. setPositiveButton ( "Share to Sketchfab" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
shareToSketchfab ();
}
})
. setNegativeButton ( "Save on device" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
saveOnDevice ();
}
})
2017-02-22 09:48:45 -05:00
. setNeutralButton ( "Cancel" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-02-22 09:48:45 -05:00
}
})
2017-02-27 16:53:05 -05:00
. create ();
d2 . show ();
// Make the textview clickable. Must be called after show()
(( TextView ) d2 . findViewById ( android . R . id . message )). setMovementMethod ( LinkMovementMethod . getInstance ());
2017-02-15 19:07:10 -05:00
}
})
2017-02-27 16:53:05 -05:00
. create ();
d . show ();
// Make the textview clickable. Must be called after show()
(( TextView ) d . findViewById ( android . R . id . message )). setMovementMethod ( LinkMovementMethod . getInstance ());
2017-02-15 19:07:10 -05:00
}
else
{
2017-06-29 10:31:59 -04:00
updateState ( previousState );
2017-02-15 19:07:10 -05:00
mToast . makeText ( getActivity (), String . format ( "Exporting map failed!" ), mToast . LENGTH_LONG ). show ();
}
2017-02-28 21:50:50 -05:00
mExportProgressDialog . dismiss ();
}
else
{
mToast . makeText ( getActivity (), String . format ( "Export canceled" ), mToast . LENGTH_LONG ). show ();
updateState ( previousState );
2017-01-26 16:46:24 -05:00
}
}
});
2017-02-28 21:50:50 -05:00
}
});
exportThread . start ();
2017-01-26 16:46:24 -05:00
}
2017-02-05 17:24:45 -05:00
2017-02-22 09:48:45 -05:00
private void saveDatabase ( String fileName )
{
final String newDatabasePath = mWorkingDirectory + fileName + ".db" ;
final String newDatabasePathHuman = mWorkingDirectoryHuman + fileName + ".db" ;
mProgressDialog . setTitle ( "Saving" );
if ( mOpenedDatabasePath . equals ( newDatabasePath ))
{
mProgressDialog . setMessage ( String . format ( "Please wait while updating \"%s\"..." , newDatabasePathHuman ));
}
else
{
mProgressDialog . setMessage ( String . format ( "Please wait while saving \"%s\"..." , newDatabasePathHuman ));
}
mProgressDialog . show ();
2017-06-29 10:31:59 -04:00
final State previousState = mState ;
2017-02-22 09:48:45 -05:00
updateState ( State . STATE_PROCESSING );
Thread saveThread = new Thread ( new Runnable () {
public void run () {
RTABMapLib . save ( newDatabasePath ); // save
runOnUiThread ( new Runnable () {
public void run () {
2017-07-24 20:24:16 -04:00
String msg ;
2017-02-22 09:48:45 -05:00
if ( mOpenedDatabasePath . equals ( newDatabasePath ))
{
2017-07-24 20:24:16 -04:00
msg = String . format ( "Database \"%s\" updated." , newDatabasePathHuman );
2017-02-22 09:48:45 -05:00
}
else
{
2017-07-24 20:24:16 -04:00
msg = String . format ( "Database saved to \"%s\"." , newDatabasePathHuman );
2017-02-22 09:48:45 -05:00
}
2017-07-24 20:24:16 -04:00
mToast . makeText ( getActivity (), msg , mToast . LENGTH_LONG ). show ();
// build notification
Intent intent = new Intent ( getActivity (), RTABMapActivity . class );
// use System.currentTimeMillis() to have a unique ID for the pending intent
PendingIntent pIntent = PendingIntent . getActivity ( getActivity (), ( int ) System . currentTimeMillis (), intent , 0 );
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( getActivity ());
boolean notifySound = sharedPref . getBoolean ( getString ( R . string . pref_key_notification_sound ), Boolean . parseBoolean ( getString ( R . string . pref_default_notification_sound )));
Notification n = new Notification . Builder ( getActivity ())
. setContentTitle ( getString ( R . string . app_name ))
. setContentText ( msg )
. setSmallIcon ( R . drawable . ic_launcher )
. setContentIntent ( pIntent )
. setDefaults ( notifySound ? Notification . DEFAULT_SOUND : 0 )
. setAutoCancel ( true ). build ();
NotificationManager notificationManager =
( NotificationManager ) getSystemService ( NOTIFICATION_SERVICE );
notificationManager . notify ( 0 , n );
resetNoTouchTimer ( true );
2017-02-22 09:48:45 -05:00
if ( ! mItemDataRecorderMode . isChecked ())
{
mOpenedDatabasePath = newDatabasePath ;
}
mProgressDialog . dismiss ();
2017-06-29 10:31:59 -04:00
updateState ( previousState );
2017-02-22 09:48:45 -05:00
}
});
}
});
saveThread . start ();
}
2017-02-15 19:07:10 -05:00
private void saveOnDevice ()
{
AlertDialog . Builder builder = new AlertDialog . Builder ( this );
2017-06-21 17:14:40 -04:00
builder . setTitle ( "Model Name:" );
2017-02-15 19:07:10 -05:00
final EditText input = new EditText ( this );
input . setInputType ( InputType . TYPE_CLASS_TEXT );
builder . setView ( input );
if ( mOpenedDatabasePath . isEmpty ())
{
String timeStamp = new SimpleDateFormat ( "yyMMdd-HHmmss" ). format ( mDateOnPause );
input . setText ( timeStamp );
}
else
{
File f = new File ( mOpenedDatabasePath );
String name = f . getName ();
input . setText ( name . substring ( 0 , name . lastIndexOf ( "." )));
}
input . setImeOptions ( EditorInfo . IME_FLAG_NO_EXTRACT_UI );
input . setSelectAllOnFocus ( true );
input . selectAll ();
builder . setCancelable ( false );
builder . setNegativeButton ( "Cancel" , new DialogInterface . OnClickListener () {
@Override
public void onClick ( DialogInterface dialog , int which )
{
dialog . dismiss ();
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-02-15 19:07:10 -05:00
}
});
builder . setPositiveButton ( "Ok" , new DialogInterface . OnClickListener () {
@Override
public void onClick ( DialogInterface dialog , int which )
{
final String fileName = input . getText (). toString ();
dialog . dismiss ();
if ( ! fileName . isEmpty ())
{
2017-06-21 17:14:40 -04:00
File newFile = new File ( mWorkingDirectory + RTABMAP_EXPORT_DIR + fileName + ".zip" );
2017-02-15 19:07:10 -05:00
if ( newFile . exists ())
{
new AlertDialog . Builder ( getActivity ())
. setTitle ( "File Already Exists" )
. setMessage ( "Do you want to overwrite the existing file?" )
. setPositiveButton ( "Yes" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
2017-06-21 17:14:40 -04:00
writeExportedFiles ( fileName );
2017-02-15 19:07:10 -05:00
}
})
. setNegativeButton ( "No" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
saveOnDevice ();
}
})
. show ();
}
else
{
2017-06-21 17:14:40 -04:00
writeExportedFiles ( fileName );
2017-02-15 19:07:10 -05:00
}
}
}
});
AlertDialog alertToShow = builder . create ();
alertToShow . getWindow (). setSoftInputMode ( WindowManager . LayoutParams . SOFT_INPUT_STATE_VISIBLE );
alertToShow . show ();
}
2017-06-21 17:14:40 -04:00
private void writeExportedFiles ( final String fileName )
2017-03-05 13:05:26 -05:00
{
2017-06-21 17:14:40 -04:00
Log . i ( TAG , String . format ( "Write exported mesh to \"%s\"" , fileName ));
mProgressDialog . setTitle ( "Saving to sd-card" );
mProgressDialog . setMessage ( String . format ( "Compressing the files..." ));
mProgressDialog . show ();
Thread workingThread = new Thread ( new Runnable () {
public void run () {
boolean success = false ;
File tmpDir = new File ( mWorkingDirectory + RTABMAP_TMP_DIR );
tmpDir . mkdirs ();
String [] fileNames = Util . loadFileList ( mWorkingDirectory + RTABMAP_TMP_DIR , false );
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "Deleting %d files in \"%s\"" , fileNames . length , mWorkingDirectory + RTABMAP_TMP_DIR ));
2017-06-10 21:45:51 -04:00
for ( int i = 0 ; i < fileNames . length ; ++ i )
{
2017-06-21 17:14:40 -04:00
File f = new File ( mWorkingDirectory + RTABMAP_TMP_DIR + "/" + fileNames [ i ] );
if ( f . delete ())
{
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "Deleted \"%s\"" , f . getPath ()));
}
else
{
if ( ! DISABLE_LOG ) Log . i ( TAG , String . format ( "Failed deleting \"%s\"" , f . getPath ()));
}
2017-06-10 21:45:51 -04:00
}
2017-06-21 17:14:40 -04:00
File exportDir = new File ( mWorkingDirectory + RTABMAP_EXPORT_DIR );
exportDir . mkdirs ();
2017-06-10 21:45:51 -04:00
2017-06-21 17:14:40 -04:00
final String pathHuman = mWorkingDirectoryHuman + RTABMAP_EXPORT_DIR + fileName + ".zip" ;
2017-08-31 11:10:46 -04:00
final String zipOutput = mWorkingDirectory + RTABMAP_EXPORT_DIR + fileName + ".zip" ;
2017-06-21 17:14:40 -04:00
if ( RTABMapLib . writeExportedMesh ( mWorkingDirectory + RTABMAP_TMP_DIR , RTABMAP_TMP_FILENAME ))
2017-08-31 11:10:46 -04:00
{
2017-06-21 17:14:40 -04:00
fileNames = Util . loadFileList ( mWorkingDirectory + RTABMAP_TMP_DIR , false );
if ( fileNames . length > 0 )
{
String [] filesToZip = new String [ fileNames . length ] ;
for ( int i = 0 ; i < fileNames . length ; ++ i )
{
filesToZip [ i ] = mWorkingDirectory + RTABMAP_TMP_DIR + "/" + fileNames [ i ] ;
}
File toZIPFile = new File ( zipOutput );
toZIPFile . delete ();
try
{
Util . zip ( filesToZip , zipOutput );
success = true ;
}
catch ( IOException e )
{
final String msg = e . getMessage ();
runOnUiThread ( new Runnable () {
public void run () {
mToast . makeText ( getActivity (), String . format ( "Exporting mesh \"%s\" failed! Error=%s" , pathHuman , msg ), mToast . LENGTH_LONG ). show ();
}
});
}
}
2017-06-10 21:45:51 -04:00
}
2017-06-21 17:14:40 -04:00
if ( success )
2017-06-10 21:45:51 -04:00
{
2017-06-21 17:14:40 -04:00
runOnUiThread ( new Runnable () {
public void run () {
mProgressDialog . dismiss ();
2017-07-24 20:24:16 -04:00
2017-08-31 11:10:46 -04:00
// Send to...
Intent shareIntent = new Intent ();
shareIntent . setAction ( Intent . ACTION_SEND );
shareIntent . putExtra ( Intent . EXTRA_STREAM , Uri . fromFile ( new File ( zipOutput )));
shareIntent . setType ( "application/zip" );
startActivity ( Intent . createChooser ( shareIntent , String . format ( "Mesh \"%s\" successfully exported! Share it?" , pathHuman )));
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-06-21 17:14:40 -04:00
}
});
}
else
{
runOnUiThread ( new Runnable () {
public void run () {
mProgressDialog . dismiss ();
mToast . makeText ( getActivity (), String . format ( "Exporting mesh \"%s\" failed! No files found in tmp directory!? Last export may have failed or have been canceled." , pathHuman ), mToast . LENGTH_LONG ). show ();
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-06-21 17:14:40 -04:00
}
});
2017-06-10 21:45:51 -04:00
}
2017-02-15 19:07:10 -05:00
}
2017-06-21 17:14:40 -04:00
});
workingThread . start ();
2017-02-15 19:07:10 -05:00
}
2017-02-22 09:48:45 -05:00
private void openDatabase ( final String fileName , final boolean optimize )
2017-02-05 17:24:45 -05:00
{
mOpenedDatabasePath = mWorkingDirectory + fileName ;
2017-06-20 17:29:06 -04:00
Log . i ( TAG , "Open database " + mOpenedDatabasePath );
2017-02-05 17:24:45 -05:00
SharedPreferences sharedPref = PreferenceManager . getDefaultSharedPreferences ( getActivity ());
2017-02-22 09:48:45 -05:00
final boolean databaseInMemory = sharedPref . getBoolean ( getString ( R . string . pref_key_db_in_memory ), Boolean . parseBoolean ( getString ( R . string . pref_default_db_in_memory )));
2017-02-15 19:07:10 -05:00
2017-02-22 09:48:45 -05:00
mProgressDialog . setTitle ( "Loading" );
mProgressDialog . setMessage ( String . format ( "Opening database \"%s\"..." , fileName ));
mProgressDialog . show ();
updateState ( State . STATE_PROCESSING );
Thread openThread = new Thread ( new Runnable () {
public void run () {
2017-06-21 17:14:40 -04:00
2017-06-20 17:29:06 -04:00
final String tmpDatabase = mWorkingDirectory + RTABMAP_TMP_DB ;
final int status = RTABMapLib . openDatabase2 ( mOpenedDatabasePath , tmpDatabase , databaseInMemory , optimize );
2017-02-22 09:48:45 -05:00
runOnUiThread ( new Runnable () {
public void run () {
if ( status == - 1 )
{
2017-06-20 17:29:06 -04:00
updateState ( State . STATE_IDLE );
2017-03-26 13:40:25 -04:00
mProgressDialog . dismiss ();
2017-02-22 09:48:45 -05:00
new AlertDialog . Builder ( getActivity ())
. setCancelable ( false )
. setTitle ( "Error" )
. setMessage ( "The map is loaded but optimization of the map's graph has "
+ "failed, so the map cannot be shown. Change the Graph Optimizer approach used"
+ " or enable/disable if the graph is optimized from graph "
+ "end in \"Settings -> Mapping...\" and try opening again." )
. setPositiveButton ( "Open Settings" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
Intent intent = new Intent ( getActivity (), SettingsActivity . class );
startActivity ( intent );
2017-02-27 16:53:05 -05:00
mBlockBack = true ;
2017-02-22 09:48:45 -05:00
}
})
. setNegativeButton ( "Close" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
}
})
. show ();
}
2017-04-18 17:30:14 -04:00
else if ( status == - 2 )
{
2017-06-20 17:29:06 -04:00
updateState ( State . STATE_IDLE );
2017-04-18 17:30:14 -04:00
mProgressDialog . dismiss ();
new AlertDialog . Builder ( getActivity ())
. setCancelable ( false )
. setTitle ( "Error" )
. setMessage ( "Failed to open database: Out of memory! Try "
+ "again after lowering Point Cloud Density in Settings." )
. setPositiveButton ( "Open Settings" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
Intent intent = new Intent ( getActivity (), SettingsActivity . class );
startActivity ( intent );
mBlockBack = true ;
}
})
. setNegativeButton ( "Close" , new DialogInterface . OnClickListener () {
public void onClick ( DialogInterface dialog , int which ) {
}
})
. show ();
}
2017-02-22 09:48:45 -05:00
else
{
2017-06-20 17:29:06 -04:00
if ( status >= 1 && status <= 3 )
2017-02-22 09:48:45 -05:00
{
2017-06-20 17:29:06 -04:00
mProgressDialog . dismiss ();
2017-07-24 20:24:16 -04:00
resetNoTouchTimer ( true );
2017-06-20 17:29:06 -04:00
updateState ( State . STATE_VISUALIZING );
mToast . makeText ( getActivity (), String . format ( "Database loaded!" ), mToast . LENGTH_LONG ). show ();
}
else if ( ! mItemTrajectoryMode . isChecked ())
{
2017-06-28 13:59:20 -04:00
if ( mButtonCameraView . getSelectedItemPosition () == 0 )
2017-06-21 17:14:40 -04:00
{
2017-06-28 13:59:20 -04:00
setCamera ( 2 );
2017-06-21 17:14:40 -04:00
}
2017-06-20 17:29:06 -04:00
// creating meshes...
updateState ( State . STATE_IDLE );
2017-02-22 09:48:45 -05:00
mProgressDialog . setTitle ( "Loading" );
2017-03-12 21:21:09 -04:00
mProgressDialog . setMessage ( String . format ( "Database \"%s\" loaded. Please wait while rendering point clouds and meshes..." , fileName ));
2017-02-22 09:48:45 -05:00
}
2017-06-20 17:29:06 -04:00
2017-02-22 09:48:45 -05:00
}
}
});
}
});
openThread . start ();
2017-02-05 17:24:45 -05:00
}
public void copy ( File src , File dst ) throws IOException {
InputStream in = new FileInputStream ( src );
OutputStream out = new FileOutputStream ( dst );
// Transfer bytes from in to out
byte [] buf = new byte [ 1024 ] ;
int len ;
while (( len = in . read ( buf )) > 0 ) {
out . write ( buf , 0 , len );
}
in . close ();
out . close ();
}
2017-02-15 19:07:10 -05:00
private void shareToSketchfab ()
2017-01-26 16:46:24 -05:00
{
2017-02-15 19:07:10 -05:00
Intent intent = new Intent ( getActivity (), SketchfabActivity . class );
intent . putExtra ( RTABMAP_AUTH_TOKEN_KEY , mAuthToken );
intent . putExtra ( RTABMAP_WORKING_DIR_KEY , mWorkingDirectory );
if ( mOpenedDatabasePath . isEmpty ())
2017-01-26 16:46:24 -05:00
{
2017-02-15 19:07:10 -05:00
intent . putExtra ( RTABMAP_FILENAME_KEY , new SimpleDateFormat ( "yyMMdd-HHmmss" ). format ( mDateOnPause ));
2017-01-26 16:46:24 -05:00
}
else
{
2017-02-15 19:07:10 -05:00
File f = new File ( mOpenedDatabasePath );
String name = f . getName ();
intent . putExtra ( RTABMAP_FILENAME_KEY , name . substring ( 0 , name . lastIndexOf ( "." )));
2017-02-05 17:24:45 -05:00
}
2017-02-15 19:07:10 -05:00
startActivityForResult ( intent , SKETCHFAB_ACTIVITY_CODE );
2017-02-27 16:53:05 -05:00
mBlockBack = true ;
2017-02-05 17:24:45 -05:00
}
2016-02-15 19:35:24 -05:00
}