RTABMapActivity.java
Go to the documentation of this file.
00001 package com.introlab.rtabmap;
00002 
00003 import java.io.File;
00004 import java.io.FilenameFilter;
00005 
00006 import android.app.Activity;
00007 import android.app.AlertDialog;
00008 import android.app.Notification;
00009 import android.app.NotificationManager;
00010 import android.app.PendingIntent;
00011 import android.app.ProgressDialog;
00012 import android.content.ComponentName;
00013 import android.content.DialogInterface;
00014 import android.content.Intent;
00015 import android.content.ServiceConnection;
00016 import android.content.pm.PackageInfo;
00017 import android.content.pm.PackageManager;
00018 import android.content.pm.PackageManager.NameNotFoundException;
00019 import android.graphics.Point;
00020 import android.opengl.GLSurfaceView;
00021 import android.os.Bundle;
00022 import android.os.Environment;
00023 import android.os.Handler;
00024 import android.os.Debug;
00025 import android.os.IBinder;
00026 import android.text.Editable;
00027 import android.text.InputType;
00028 import android.util.Log;
00029 import android.view.Display;
00030 import android.view.Menu;
00031 import android.view.MenuItem;
00032 import android.view.MenuInflater;
00033 import android.view.MotionEvent;
00034 import android.view.View;
00035 import android.view.View.OnClickListener;
00036 import android.view.WindowManager;
00037 import android.widget.EditText;
00038 import android.widget.LinearLayout;
00039 import android.widget.TextView;
00040 import android.widget.Toast;
00041 
00042 import com.google.atap.tangoservice.Tango;
00043 
00044 // The main activity of the application. This activity shows debug information
00045 // and a glSurfaceView that renders graphic content.
00046 public class RTABMapActivity extends Activity implements OnClickListener {
00047 
00048   // Tag for debug logging.
00049   private static final String TAG = RTABMapActivity.class.getSimpleName();
00050 
00051   // The minimum Tango Core version required from this application.
00052   private static final int  MIN_TANGO_CORE_VERSION = 6804;
00053 
00054   // The package name of Tang Core, used for checking minimum Tango Core version.
00055   private static final String TANGO_PACKAGE_NAME = "com.projecttango.tango";
00056   
00057   public static final String EXTRA_KEY_PERMISSIONTYPE = "PERMISSIONTYPE";
00058   public static final String EXTRA_VALUE_ADF = "ADF_LOAD_SAVE_PERMISSION";
00059 
00060   // GLSurfaceView and renderer, all of the graphic content is rendered
00061   // through OpenGL ES 2.0 in native code.
00062   private Renderer mRenderer;
00063   private GLSurfaceView mGLView;
00064   
00065   ProgressDialog mProgressDialog;
00066 
00067   // Screen size for normalizing the touch input for orbiting the render camera.
00068   private Point mScreenSize = new Point();
00069 
00070   private MenuItem mItemPause;
00071   private MenuItem mItemSave;
00072   private MenuItem mItemOpen;
00073   private MenuItem mItemPostProcessing;
00074   private MenuItem mItemExport;
00075   private MenuItem mItemLocalizationMode;
00076   private MenuItem mItemTrajectoryMode;
00077   
00078   private String mOpenedDatabasePath = "";
00079   private String mTempDatabasePath = "";
00080   private String mNewDatabasePath = "";
00081   private String mWorkingDirectory = "";
00082   
00083   private int mMaxDepthIndex = 5;
00084   private int mMeshAngleToleranceIndex = 1;
00085   private int mMeshTriangleSizeIndex = 0;
00086   
00087   private int mParamUpdateRateHzIndex = 1;
00088   private int mParamTimeThrMsIndex = 4;
00089   private int mParamMaxFeaturesIndex = 4;
00090   private int mParamLoopThrMsIndex = 1;
00091   private int mParamOptimizeErrorIndex = 3;
00092   
00093   final String[] mUpdateRateValues = {"0.5", "1", "2", "Max"};
00094   final String[] mTimeThrValues = {"400", "500", "600", "700", "800", "900", "1000", "1100", "1200", "1300", "1400", "1500", "No Limit"};
00095   final String[] mMaxFeaturesValues = {"Disabled", "100", "200", "300", "400", "500", "600", "700", "800", "900", "1000", "No Limit"};
00096   final String[] mLoopThrValues = {"Disabled", "0.11", "0.20", "0.30", "0.40", "0.50", "0.60", "0.70", "0.80", "0.90"};
00097   final String[] mOptimizeErrorValues = {"Disabled", "0.01", "0.025", "0.05", "0.1", "0.2", "0.35", "0.5", "1"};
00098   
00099   private LinearLayout mLayoutDebug;
00100   
00101   private int mTotalLoopClosures = 0;
00102   
00103   private Toast mToast = null;
00104   
00105   //Tango Service connection.
00106   ServiceConnection mTangoServiceConnection = new ServiceConnection() {
00107      public void onServiceConnected(ComponentName name, IBinder service) {
00108        if(!RTABMapLib.onTangoServiceConnected(service))
00109        {
00110            mToast.makeText(getApplicationContext(), 
00111                                 String.format("Failed to intialize Tango!"), mToast.LENGTH_SHORT).show();
00112        }
00113      }
00114 
00115      public void onServiceDisconnected(ComponentName name) {
00116        // Handle this if you need to gracefully shutdown/retry
00117        // in the event that Tango itself crashes/gets upgraded while running.
00118        mToast.makeText(getApplicationContext(), 
00119                                 String.format("Tango disconnected!"), mToast.LENGTH_SHORT).show();
00120      }
00121    };
00122   
00123   @Override
00124   protected void onCreate(Bundle savedInstanceState) {
00125     super.onCreate(savedInstanceState);
00126     setTitle(R.string.menu_name);
00127 
00128     // Query screen size, the screen size is used for computing the normalized
00129     // touch point.
00130     Display display = getWindowManager().getDefaultDisplay();
00131     display.getSize(mScreenSize);
00132     
00133     getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
00134 
00135     // Setting content view of this activity.
00136     setContentView(R.layout.activity_rtabmap);
00137 
00138     // Buttons for selecting camera view and Set up button click listeners.
00139     findViewById(R.id.first_person_button).setOnClickListener(this);
00140     findViewById(R.id.third_person_button).setOnClickListener(this);
00141     findViewById(R.id.top_down_button).setOnClickListener(this);
00142     
00143     mToast = Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT);
00144 
00145     // OpenGL view where all of the graphics are drawn.
00146     mGLView = (GLSurfaceView) findViewById(R.id.gl_surface_view);
00147     
00148     // Configure OpenGL renderer
00149     mGLView.setEGLContextClientVersion(2);
00150 
00151     // Configure the OpenGL renderer.
00152     mRenderer = new Renderer();
00153     mGLView.setRenderer(mRenderer);
00154     
00155     mLayoutDebug = (LinearLayout) findViewById(R.id.debug_layout);
00156     mLayoutDebug.setVisibility(LinearLayout.GONE);
00157     
00158     mProgressDialog = new ProgressDialog(this);
00159     mRenderer.setProgressDialog(mProgressDialog);
00160 
00161     // Check if the Tango Core is out dated.
00162     if (!CheckTangoCoreVersion(MIN_TANGO_CORE_VERSION)) {
00163       mToast.makeText(this, "Tango Core out dated, please update in Play Store", mToast.LENGTH_LONG).show();
00164       finish();
00165       return;
00166     }   
00167     
00168     mOpenedDatabasePath = "";
00169     mTempDatabasePath = "";
00170     mNewDatabasePath = "";
00171     mWorkingDirectory = "";
00172     mTotalLoopClosures = 0;
00173     
00174     if(Environment.getExternalStorageState().compareTo(Environment.MEDIA_MOUNTED)==0)
00175     {
00176         File extStore = Environment.getExternalStorageDirectory();
00177         mWorkingDirectory = extStore.getAbsolutePath() + "/" + getString(R.string.app_name) + "/";
00178         extStore = new File(mWorkingDirectory);
00179         extStore.mkdirs();
00180         mTempDatabasePath = mWorkingDirectory + "rtabmap.tmp.db";
00181         extStore = new File(mTempDatabasePath);
00182         
00183         if(extStore.exists())
00184         {
00185                 extStore.delete();
00186         }       
00187     }
00188     else
00189     {
00190         // show warning that data cannot be saved!
00191                 mToast.makeText(getApplicationContext(), 
00192                                 String.format("Failed to get external storage path (SD-CARD, state=%s). Saving disabled.", 
00193                                                 Environment.getExternalStorageState()), mToast.LENGTH_LONG).show();
00194     }
00195     
00196     RTABMapLib.onCreate(this);
00197     RTABMapLib.openDatabase(mTempDatabasePath);
00198   }
00199   
00200   @Override
00201   protected void onActivityResult(int requestCode, int resultCode, Intent data) {
00202         // Check which request we're responding to
00203         if (requestCode == Tango.TANGO_INTENT_ACTIVITYCODE) {
00204                 // Make sure the request was successful
00205                 if (resultCode == RESULT_CANCELED) {
00206                         mToast.makeText(this, "Motion Tracking Permissions Required!",
00207                                         mToast.LENGTH_SHORT).show();
00208                         finish();
00209                 }
00210         }
00211   }
00212 
00213   @Override
00214   protected void onResume() {
00215     super.onResume();
00216     
00217     TangoInitializationHelper.bindTangoService(this, mTangoServiceConnection);
00218     
00219     Log.i(TAG, String.format("onResume()"));
00220     
00221     if (Tango.hasPermission(this, Tango.PERMISSIONTYPE_MOTION_TRACKING)) {
00222 
00223         mGLView.onResume();
00224         
00225         mTotalLoopClosures = 0;
00226         if(mItemOpen != null)
00227         {
00228             mItemOpen.setEnabled(false);
00229             mItemPause.setChecked(false);
00230             mItemSave.setEnabled(false);
00231                 mItemExport.setEnabled(false);
00232                 mItemPostProcessing.setEnabled(false);
00233         }
00234 
00235     } else {
00236         Log.i(TAG, String.format("Asking for motion tracking permission"));
00237         startActivityForResult(
00238                 Tango.getRequestPermissionIntent(Tango.PERMISSIONTYPE_MOTION_TRACKING),
00239                 Tango.TANGO_INTENT_ACTIVITYCODE);
00240     }
00241   }
00242 
00243   @Override
00244   protected void onPause() {
00245     super.onPause();
00246     mGLView.onPause();
00247     
00248     // Delete all the non-OpenGl resources.
00249     RTABMapLib.onPause();
00250     mOpenedDatabasePath = "";
00251     RTABMapLib.openDatabase(mTempDatabasePath);
00252     
00253     unbindService(mTangoServiceConnection);
00254   }
00255 
00256   @Override
00257   public void onClick(View v) {
00258     // Handle button clicks.
00259     switch (v.getId()) {
00260     case R.id.first_person_button:
00261       RTABMapLib.setCamera(0);
00262       break;
00263     case R.id.third_person_button:
00264       RTABMapLib.setCamera(1);
00265       break;
00266     case R.id.top_down_button:
00267       RTABMapLib.setCamera(2);
00268       break;
00269     default:
00270       return;
00271     }
00272   }
00273 
00274   @Override
00275   public boolean onTouchEvent(MotionEvent event) {
00276     // Pass the touch event to the native layer for camera control.
00277     // Single touch to rotate the camera around the device.
00278     // Two fingers to zoom in and out.
00279     int pointCount = event.getPointerCount();
00280     if (pointCount == 1) {
00281       float normalizedX = event.getX(0) / mScreenSize.x;
00282       float normalizedY = event.getY(0) / mScreenSize.y;
00283       RTABMapLib.onTouchEvent(1, 
00284           event.getActionMasked(), normalizedX, normalizedY, 0.0f, 0.0f);
00285     }
00286     if (pointCount == 2) {
00287       if (event.getActionMasked() == MotionEvent.ACTION_POINTER_UP) {
00288         int index = event.getActionIndex() == 0 ? 1 : 0;
00289         float normalizedX = event.getX(index) / mScreenSize.x;
00290         float normalizedY = event.getY(index) / mScreenSize.y;
00291         RTABMapLib.onTouchEvent(1, 
00292           MotionEvent.ACTION_DOWN, normalizedX, normalizedY, 0.0f, 0.0f);
00293       } else {
00294         float normalizedX0 = event.getX(0) / mScreenSize.x;
00295         float normalizedY0 = event.getY(0) / mScreenSize.y;
00296         float normalizedX1 = event.getX(1) / mScreenSize.x;
00297         float normalizedY1 = event.getY(1) / mScreenSize.y;
00298         RTABMapLib.onTouchEvent(2, event.getActionMasked(),
00299             normalizedX0, normalizedY0, normalizedX1, normalizedY1);
00300       }
00301     }
00302     return true;
00303   }
00304   
00305   @Override
00306   public boolean onCreateOptionsMenu(Menu menu) {
00307           Log.i(TAG, "called onCreateOptionsMenu;");
00308           
00309           MenuInflater inflater = getMenuInflater();
00310           inflater.inflate(R.menu.optionmenu, menu);
00311           
00312           mItemPause = menu.findItem(R.id.pause);
00313           mItemSave = menu.findItem(R.id.save);
00314           mItemOpen = menu.findItem(R.id.open);
00315           mItemPostProcessing = menu.findItem(R.id.post_processing);
00316           mItemExport = menu.findItem(R.id.export);
00317           mItemLocalizationMode = menu.findItem(R.id.localization_mode);
00318           mItemTrajectoryMode = menu.findItem(R.id.trajectory_mode);
00319           mItemSave.setEnabled(false);
00320           mItemExport.setEnabled(false);
00321           mItemOpen.setEnabled(false);
00322           mItemPostProcessing.setEnabled(false);
00323           
00324           return true;
00325   }
00326   
00327   private void updateStatsUI(
00328                   int nodes, 
00329                   int words, 
00330                   int points, 
00331                   int polygons,
00332                   float updateTime, 
00333                   int loopClosureId,
00334                   int highestHypId,
00335                   int databaseMemoryUsed,
00336                   int inliers,
00337                   int featuresExtracted,
00338                   float hypothesis,
00339                   int nodesDrawn,
00340                   float fps,
00341                   int rejected)
00342   {
00343           if(mItemPause!=null)
00344           {
00345                   ((TextView)findViewById(R.id.status)).setText(mItemPause.isChecked()?"Paused":mItemLocalizationMode.isChecked()?String.format("Localization (%s Hz)", mUpdateRateValues[mParamUpdateRateHzIndex]):String.format("Mapping (%s Hz)", mUpdateRateValues[mParamUpdateRateHzIndex]));
00346           }
00347           
00348           ((TextView)findViewById(R.id.points)).setText(String.valueOf(points));
00349           ((TextView)findViewById(R.id.polygons)).setText(String.valueOf(polygons));
00350           ((TextView)findViewById(R.id.nodes)).setText(String.format("%d (%d shown)", nodes, nodesDrawn));
00351           ((TextView)findViewById(R.id.words)).setText(String.valueOf(words));
00352           ((TextView)findViewById(R.id.memory)).setText(String.valueOf(Debug.getNativeHeapAllocatedSize()/(1024*1024)));
00353           ((TextView)findViewById(R.id.db_size)).setText(String.valueOf(databaseMemoryUsed));
00354           ((TextView)findViewById(R.id.inliers)).setText(String.valueOf(inliers));
00355           ((TextView)findViewById(R.id.features)).setText(String.format("%d / %s", featuresExtracted, mMaxFeaturesValues[mParamMaxFeaturesIndex]));
00356           ((TextView)findViewById(R.id.update_time)).setText(String.format("%.3f / %s", updateTime, mTimeThrValues[mParamTimeThrMsIndex]));
00357           ((TextView)findViewById(R.id.hypothesis)).setText(String.format("%.3f / %s (%d)", hypothesis, mLoopThrValues[mParamLoopThrMsIndex], loopClosureId>0?loopClosureId:highestHypId));
00358           ((TextView)findViewById(R.id.fps)).setText(String.format("%.3f Hz", fps));
00359           if(mItemPause!=null && !mItemPause.isChecked())
00360           {
00361                   if(loopClosureId > 0)
00362                   {
00363                           ++mTotalLoopClosures;
00364         
00365                           mToast.setText("Loop closure detected!");
00366                           mToast.show();
00367                   }
00368                   else if(rejected > 0 && inliers >= 15)
00369                   {
00370                           mToast.setText("Loop closure rejected after graph optimization.");
00371                           mToast.show();
00372                   }
00373           }
00374           ((TextView)findViewById(R.id.total_loop)).setText(String.valueOf(mTotalLoopClosures));
00375   }
00376   
00377   // called from jni
00378   public void updateStatsCallback(
00379                   final int nodes, 
00380                   final int words, 
00381                   final int points, 
00382                   final int polygons,
00383                   final float updateTime, 
00384                   final int loopClosureId,
00385                   final int highestHypId,
00386                   final int databaseMemoryUsed,
00387                   final int inliers,
00388                   final int features,
00389                   final float hypothesis,
00390                   final int nodesDrawn,
00391                   final float fps,
00392                   final int rejected)
00393   {
00394           Log.i(TAG, String.format("updateStatsCallback()"));
00395 
00396           runOnUiThread(new Runnable() {
00397                     public void run() {
00398                         updateStatsUI(nodes, words, points, polygons, updateTime, loopClosureId, highestHypId, databaseMemoryUsed, inliers, features, hypothesis, nodesDrawn, fps, rejected);
00399                     } 
00400                 });
00401   }
00402   
00403   private void rtabmapInitEventUI(
00404                   int status, 
00405                   String msg)
00406   {
00407           Log.i(TAG, String.format("rtabmapInitEventsUI() status=%d msg=%s", status, msg));
00408           
00409           ((TextView)findViewById(R.id.status)).setText(
00410                           status == 1 && msg.isEmpty()?mItemPause!=null&&mItemPause.isChecked()?"Paused":mItemLocalizationMode!=null&&mItemLocalizationMode.isChecked()?"Localization":"Mapping":msg);
00411           
00412           /*0=kInitializing,
00413                 1=kInitialized,
00414                 2=kClosing,
00415                 3=kClosed,
00416                 4=kInfo,
00417                 5=kError*/
00418           
00419                 if(status == 3)
00420                 {
00421                         msg = "";
00422                         if(!mNewDatabasePath.isEmpty())
00423                         {
00424                                 boolean removed = true;
00425                                 File outputFile = new File(mNewDatabasePath);
00426                                 if(outputFile.exists())
00427                                 {
00428                                         removed = outputFile.delete();
00429                                 }
00430                                 if(removed)
00431                                 {
00432                                         File tempFile = new File(mTempDatabasePath);
00433                                         if(tempFile.renameTo(outputFile))
00434                                         {
00435                                                 msg = String.format("Database saved to \"%s\".", mNewDatabasePath);
00436                                                 
00437                                                 Intent intent = new Intent(this, RTABMapActivity.class);
00438                                                 // use System.currentTimeMillis() to have a unique ID for the pending intent
00439                                                 PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);
00440 
00441                                                 // build notification
00442                                                 // the addAction re-use the same intent to keep the example short
00443                                                 Notification n  = new Notification.Builder(this)
00444                                                         .setContentTitle(getString(R.string.app_name))
00445                                                         .setContentText(mNewDatabasePath + " saved!")
00446                                                         .setSmallIcon(R.drawable.ic_launcher)
00447                                                         .setContentIntent(pIntent)
00448                                                         .setAutoCancel(true).build();
00449                                                     
00450                                                   
00451                                                 NotificationManager notificationManager = 
00452                                                   (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
00453 
00454                                                 notificationManager.notify(0, n); 
00455                                         }
00456                                         else
00457                                         {
00458                                                 msg = String.format("Failed to rename temporary database from \"%s\" to \"%s\".",
00459                                                                 mTempDatabasePath, mNewDatabasePath);
00460                                         }
00461                                 }
00462                                 else
00463                                 {
00464                                         msg = String.format("Failed to overwrite the database \"%s\". The temporary database is still correctly saved at \"%s\".",
00465                                                         mNewDatabasePath, mTempDatabasePath);
00466                                 }
00467                         }
00468                         else if(!mOpenedDatabasePath.isEmpty())
00469                         {
00470                                 msg = String.format("Database \"%s\" updated.", mOpenedDatabasePath);
00471                         }
00472 
00473                         if(!msg.isEmpty())
00474                         {
00475                                 mToast.makeText(this, msg, mToast.LENGTH_LONG).show();
00476                         }
00477                         
00478                         mOpenedDatabasePath = "";
00479                         mNewDatabasePath = "";
00480                         
00481                         //restart a new scan by default
00482                         RTABMapLib.openDatabase(mTempDatabasePath);
00483                         
00484                         ((TextView)findViewById(R.id.points)).setText(String.valueOf(0));
00485                         ((TextView)findViewById(R.id.polygons)).setText(String.valueOf(0));
00486                         ((TextView)findViewById(R.id.nodes)).setText(String.valueOf(0));
00487                         ((TextView)findViewById(R.id.words)).setText(String.valueOf(0));
00488                         ((TextView)findViewById(R.id.memory)).setText(String.valueOf(Debug.getNativeHeapAllocatedSize()/(1024*1024)));
00489                         ((TextView)findViewById(R.id.db_size)).setText(String.valueOf(0));
00490                         ((TextView)findViewById(R.id.inliers)).setText(String.valueOf(0));
00491                         ((TextView)findViewById(R.id.features)).setText(String.valueOf(0));
00492                         ((TextView)findViewById(R.id.update_time)).setText(String.valueOf(0));
00493                         ((TextView)findViewById(R.id.hypothesis)).setText(String.valueOf(0));
00494                         ((TextView)findViewById(R.id.fps)).setText(String.valueOf(0));
00495                         mTotalLoopClosures = 0;
00496                         ((TextView)findViewById(R.id.total_loop)).setText(String.valueOf(mTotalLoopClosures));
00497                         
00498                         if(mItemSave!=null)
00499                         {
00500                                 if(mItemPause.isChecked())
00501                                 {
00502                                         mItemPause.setChecked(false);
00503                                         mItemOpen.setEnabled(false);
00504                                         mItemPostProcessing.setEnabled(false);
00505                                         mItemSave.setEnabled(false);
00506                                         mItemExport.setEnabled(false);
00507                                         RTABMapLib.setPausedMapping(false); // resume mapping
00508                                 }
00509                         }
00510                         mProgressDialog.dismiss();
00511                 }
00512   }
00513   
00514   //called from jni
00515   public void rtabmapInitEventCallback(
00516                   final int status, 
00517                   final String msg)
00518   {
00519           Log.i(TAG, String.format("rtabmapInitEventCallback()"));
00520 
00521           runOnUiThread(new Runnable() {
00522                     public void run() {
00523                         rtabmapInitEventUI(status, msg);
00524                     } 
00525                 });
00526   }
00527   
00528   private void tangoEventUI(
00529                   int type, 
00530                   String key,
00531                   String value)
00532   {
00544           String str = null;
00545           if(key.equals("TangoServiceException"))
00546                   str = String.format("Tango service exception: %s", value);
00547           else if(key.equals("FisheyeOverExposed"))
00548                   ;//str = String.format("The fisheye image is over exposed with average pixel value %s px.", value);
00549           else if(key.equals("FisheyeUnderExposed"))
00550                   ;//str = String.format("The fisheye image is under exposed with average pixel value %s px.", value);
00551           else if(key.equals("ColorOverExposed")) 
00552                   ;//str = String.format("The color image is over exposed with average pixel value %s px.", value);
00553           else if(key.equals("ColorUnderExposed")) 
00554                   ;//str = String.format("The color image is under exposed with average pixel value %s px.", value);
00555           else if(key.equals("CameraTango")) 
00556                   str = value;
00557           else if(key.equals("TooFewFeaturesTracked")) 
00558           {
00559                   if(!value.equals("0"))
00560                   {
00561                           str = String.format("Too few features (%s) were tracked in the fisheye image. This may result in poor odometry!", value);
00562                   }
00563           }
00564           else  
00565           {
00566                   str = String.format("Unknown Tango event detected!? (type=%d)", type);
00567           }
00568           if(str!=null)
00569           {
00570                   mToast.setText(str);
00571                   mToast.show();
00572           }
00573   }
00574   
00575   //called from jni
00576   public void tangoEventCallback(
00577                   final int type, 
00578                   final String key,
00579                   final String value)
00580   {
00581           if(mItemPause != null && !mItemPause.isChecked())
00582           {
00583                   runOnUiThread(new Runnable() {
00584                             public void run() {
00585                                 tangoEventUI(type, key, value);
00586                             } 
00587                         });
00588           }
00589   }
00590   
00591   private boolean CheckTangoCoreVersion(int minVersion) {
00592     int versionNumber = 0;
00593     String packageName = TANGO_PACKAGE_NAME;
00594     try {
00595       PackageInfo pi = getApplicationContext().getPackageManager().getPackageInfo(packageName,
00596           PackageManager.GET_META_DATA);
00597       versionNumber = pi.versionCode;
00598     } catch (NameNotFoundException e) {
00599       e.printStackTrace();
00600     }
00601     return (minVersion <= versionNumber);
00602   }
00603   
00604   private RTABMapActivity getActivity() {return this;}
00605   
00606   private String[] loadFileList(String directory) {
00607             File path = new File(directory); 
00608             String fileList[];
00609             try {
00610                 path.mkdirs();
00611             }
00612             catch(SecurityException e) {
00613                 Log.e(TAG, "unable to write on the sd card " + e.toString());
00614             }
00615             if(path.exists()) {
00616                 FilenameFilter filter = new FilenameFilter() {
00617 
00618                     @Override
00619                     public boolean accept(File dir, String filename) {
00620                         File sel = new File(dir, filename);
00621                         return filename.endsWith(".db");
00622                     }
00623 
00624                 };
00625                 fileList = path.list(filter);
00626             }
00627             else {
00628                 fileList = new String[0];
00629             }
00630             return fileList;
00631         }
00632   
00633   public boolean onOptionsItemSelected(MenuItem item) {
00634           Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
00635           int itemId = item.getItemId();
00636       if (itemId == R.id.pause)
00637       {
00638           item.setChecked(!item.isChecked());
00639           mItemSave.setEnabled(item.isChecked());
00640                   mItemExport.setEnabled(item.isChecked());
00641           mItemOpen.setEnabled(item.isChecked());
00642           mItemPostProcessing.setEnabled(item.isChecked());
00643          // mItemSave.setEnabled(item.isChecked() && !mWorkingDirectory.isEmpty());
00644           if(item.isChecked())
00645           {
00646                   RTABMapLib.setPausedMapping(true);
00647                   ((TextView)findViewById(R.id.status)).setText("Paused");
00648           }
00649           else
00650           {
00651                   RTABMapLib.setPausedMapping(false);
00652                   ((TextView)findViewById(R.id.status)).setText(mItemLocalizationMode.isChecked()?"Localization":"Mapping");
00653           }
00654       } 
00655       else if (itemId == R.id.detect_more_loop_closures)
00656       {
00657                         mProgressDialog.setTitle("Post-Processing");
00658                         mProgressDialog.setMessage(String.format("Please wait while detecting more loop closures..."));
00659                         mProgressDialog.show();
00660                         
00661                         Thread workingThread = new Thread(new Runnable() {
00662                                     public void run() {
00663                                         final int loopDetected = RTABMapLib.postProcessing(2);
00664                                         runOnUiThread(new Runnable() {
00665                                                 public void run() {
00666                                                                 mProgressDialog.dismiss();
00667                                                                 if(loopDetected >= 0)
00668                                                                 {
00669                                                                         mTotalLoopClosures+=loopDetected;
00670                                                                         mToast.makeText(getActivity(), String.format("Detection done! %d new loop closure(s) added.", loopDetected), mToast.LENGTH_SHORT).show();
00671                                                                 }
00672                                                                 else if(loopDetected < 0)
00673                                                                 {
00674                                                                         mToast.makeText(getActivity(), String.format("Detection failed!"), mToast.LENGTH_SHORT).show();
00675                                                                 }
00676                                                 }
00677                                         });
00678                                     } 
00679                         });
00680                         workingThread.start();
00681       }
00682       else if (itemId == R.id.global_graph_optimization)
00683       {
00684                         mProgressDialog.setTitle("Post-Processing");
00685                         mProgressDialog.setMessage(String.format("Global graph optimization..."));
00686                         mProgressDialog.show();
00687                         
00688                         Thread workingThread = new Thread(new Runnable() {
00689                                     public void run() {
00690                                         final int value = RTABMapLib.postProcessing(0);
00691                                         runOnUiThread(new Runnable() {
00692                                                 public void run() {
00693                                                                 mProgressDialog.dismiss();
00694                                                                 if(value >= 0)
00695                                                                 {
00696                                                                         mToast.makeText(getActivity(), String.format("Optimization done!"), mToast.LENGTH_SHORT).show();
00697                                                                 }
00698                                                                 else if(value < 0)
00699                                                                 {
00700                                                                         mToast.makeText(getActivity(), String.format("Optimization failed!"), mToast.LENGTH_SHORT).show();
00701                                                                 }
00702                                                 }
00703                                         });
00704                                     } 
00705                         });
00706                         workingThread.start();
00707       }
00708       else if (itemId == R.id.sba)
00709       {
00710                         mProgressDialog.setTitle("Post-Processing");
00711                         mProgressDialog.setMessage(String.format("Bundle adjustement..."));
00712                         mProgressDialog.show();
00713                         
00714                         Thread workingThread = new Thread(new Runnable() {
00715                                     public void run() {
00716                                         final int value = RTABMapLib.postProcessing(1);
00717                                         runOnUiThread(new Runnable() {
00718                                                 public void run() {
00719                                                                 mProgressDialog.dismiss();
00720                                                                 if(value >= 0)
00721                                                                 {
00722                                                                         mToast.makeText(getActivity(), String.format("Optimization done!"), mToast.LENGTH_SHORT).show();
00723                                                                 }
00724                                                                 else if(value < 0)
00725                                                                 {
00726                                                                         mToast.makeText(getActivity(), String.format("Optimization failed!"), mToast.LENGTH_SHORT).show();
00727                                                                 }
00728                                                 }
00729                                         });
00730                                     } 
00731                         });
00732                         workingThread.start();
00733       }
00734       else if(itemId == R.id.debug)
00735       {
00736           item.setChecked(!item.isChecked());
00737           if(!item.isChecked())
00738           {
00739                   mLayoutDebug.setVisibility(LinearLayout.GONE);
00740           }
00741           else
00742           {
00743                   mLayoutDebug.setVisibility(LinearLayout.VISIBLE);
00744           }
00745       }
00746       else if(itemId == R.id.mesh_rendering)
00747       {
00748           item.setChecked(!item.isChecked());
00749           RTABMapLib.setMeshRendering(item.isChecked());
00750       }
00751       else if(itemId == R.id.map_shown)
00752       {
00753           item.setChecked(!item.isChecked());
00754           RTABMapLib.setMapCloudShown(item.isChecked());
00755       }
00756       else if(itemId == R.id.odom_shown)
00757       {
00758           item.setChecked(!item.isChecked());
00759           RTABMapLib.setOdomCloudShown(item.isChecked());
00760       }
00761       else if(itemId == R.id.localization_mode)
00762       {
00763           item.setChecked(!item.isChecked());
00764           RTABMapLib.setLocalizationMode(item.isChecked());
00765       }
00766       else if(itemId == R.id.trajectory_mode)
00767       {
00768           item.setChecked(!item.isChecked());
00769           RTABMapLib.setTrajectoryMode(item.isChecked());
00770       }
00771       else if(itemId == R.id.graph_optimization)
00772       {
00773           item.setChecked(!item.isChecked());
00774           RTABMapLib.setGraphOptimization(item.isChecked());
00775       }
00776       else if(itemId == R.id.nodes_filtering)
00777       {
00778           item.setChecked(!item.isChecked());
00779           RTABMapLib.setNodesFiltering(item.isChecked());
00780       }
00781       else if(itemId == R.id.graph_visible)
00782       {
00783           item.setChecked(!item.isChecked());
00784           RTABMapLib.setGraphVisible(item.isChecked());
00785       }
00786       else if(itemId == R.id.auto_exposure)
00787       {
00788           item.setChecked(!item.isChecked());
00789           RTABMapLib.setAutoExposure(item.isChecked());
00790           
00791           // restart Tango service
00792           onPause();
00793           onResume();             
00794       }
00795       else if(itemId == R.id.resolution)
00796       {
00797           item.setChecked(!item.isChecked());
00798           RTABMapLib.setFullResolution(item.isChecked());
00799       }
00800       else if(itemId == R.id.max_depth)
00801       {
00802           // get double
00803                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00804                   builder.setTitle("Max Depth (m)");
00805                   final String[] values = {"1", "2", "3", "4", "5", "No Limit"};
00806                   builder.setSingleChoiceItems(values, mMaxDepthIndex, new DialogInterface.OnClickListener() {
00807                     @Override
00808                     public void onClick(DialogInterface dialog, int which) {
00809                         dialog.dismiss();
00810                         if(which >=0 && which < 6)
00811                         {
00812                                 mMaxDepthIndex = which;
00813                                 RTABMapLib.setMaxCloudDepth(which < 5?Float.parseFloat(values[which]):0);
00814                         }
00815                     }
00816                   });
00817                   builder.show();
00818       }
00819       else if(itemId == R.id.mesh_angle_tolerance)
00820       {
00821           // get double
00822                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00823                   builder.setTitle("Mesh Angle Tolerance (deg)");
00824                   final String[] values = {"5", "10", "15", "20", "25", "30"};
00825                   builder.setSingleChoiceItems(values, mMeshAngleToleranceIndex, new DialogInterface.OnClickListener() {
00826                     @Override
00827                     public void onClick(DialogInterface dialog, int which) {
00828                         dialog.dismiss();
00829                         if(which >=0 && which < 6)
00830                         {
00831                                 mMeshAngleToleranceIndex = which;
00832                                 RTABMapLib.setMeshAngleTolerance(Float.parseFloat(values[which]));
00833                         }
00834                     }
00835                   });
00836                   builder.show();
00837       }
00838       else if(itemId == R.id.mesh_triangle_size)
00839       {
00840           // get double
00841                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00842                   builder.setTitle("Mesh Triangle Size (pixels)");
00843                   final String[] values = {"2", "3", "4", "5", "6"};
00844                   builder.setSingleChoiceItems(values, mMeshTriangleSizeIndex, new DialogInterface.OnClickListener() {
00845                     @Override
00846                     public void onClick(DialogInterface dialog, int which) {
00847                         dialog.dismiss();
00848                         if(which >=0 && which < 5)
00849                         {
00850                                 mMeshTriangleSizeIndex = which;
00851                                 RTABMapLib.setMeshTriangleSize(Integer.parseInt(values[which]));
00852                         }
00853                     }
00854                   });
00855                   builder.show();
00856       }
00857       else if(itemId == R.id.update_rate)
00858       {
00859           // get double
00860                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00861                   builder.setTitle("Update Rate (Hz)");
00862                   builder.setSingleChoiceItems(mUpdateRateValues, mParamUpdateRateHzIndex, new DialogInterface.OnClickListener() {
00863                     @Override
00864                     public void onClick(DialogInterface dialog, int which) {
00865                         dialog.dismiss();
00866                         if(which >=0 && which < mUpdateRateValues.length)
00867                         {
00868                                 mParamUpdateRateHzIndex = which;
00869                                 if(RTABMapLib.setMappingParameter("Rtabmap/DetectionRate", mUpdateRateValues[which]) != 0)
00870                                 {
00871                                         mToast.makeText(getActivity(), "Failed to set parameter \"Rtabmap/DetectionRate\"!", mToast.LENGTH_LONG).show();
00872                                 }
00873                         }
00874                     }
00875                   });
00876                   builder.show();
00877       }
00878       else if(itemId == R.id.time_threshold)
00879       {
00880           // get double
00881                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00882                   builder.setTitle("Time Threshold (ms)");
00883                   builder.setSingleChoiceItems(mTimeThrValues, mParamTimeThrMsIndex, new DialogInterface.OnClickListener() {
00884                     @Override
00885                     public void onClick(DialogInterface dialog, int which) {
00886                         dialog.dismiss();
00887                         if(which >=0 && which < mTimeThrValues.length)
00888                         {
00889                                 mParamTimeThrMsIndex = which;
00890                                 if(RTABMapLib.setMappingParameter("Rtabmap/TimeThr", which==mTimeThrValues.length-1?"0":mTimeThrValues[which]) != 0)
00891                                 {
00892                                         mToast.makeText(getActivity(), "Failed to set parameter \"Rtabmap/TimeThr\"!", mToast.LENGTH_LONG).show();
00893                                 }
00894                         }
00895                     }
00896                   });
00897                   builder.show();
00898       }
00899       else if(itemId == R.id.features)
00900       {
00901           // get double
00902                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00903                   builder.setTitle("Max Features");
00904                   builder.setSingleChoiceItems(mMaxFeaturesValues, mParamMaxFeaturesIndex, new DialogInterface.OnClickListener() {
00905                     @Override
00906                     public void onClick(DialogInterface dialog, int which) {
00907                         dialog.dismiss();
00908                         if(which >=0 && which < mMaxFeaturesValues.length)
00909                         {
00910                                 mParamMaxFeaturesIndex = which;
00911                                 if(RTABMapLib.setMappingParameter("Kp/MaxFeatures", which==0?"-1":which==mMaxFeaturesValues.length-1?"0":mMaxFeaturesValues[which]) != 0)
00912                                 {
00913                                         mToast.makeText(getActivity(),"Failed to set parameter \"Kp/MaxFeatures\"!", mToast.LENGTH_LONG).show();
00914                                 }
00915                         }
00916                     }
00917                   });
00918                   builder.show();
00919       }
00920       else if(itemId == R.id.loop_threshold)
00921       {
00922           // get double
00923                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00924                   builder.setTitle("Loop Closure Threshold");
00925                   builder.setSingleChoiceItems(mLoopThrValues, mParamLoopThrMsIndex, new DialogInterface.OnClickListener() {
00926                     @Override
00927                     public void onClick(DialogInterface dialog, int which) {
00928                         dialog.dismiss();
00929                         if(which >=0 && which < mLoopThrValues.length)
00930                         {
00931                                 mParamLoopThrMsIndex = which;
00932                                 if(RTABMapLib.setMappingParameter("Rtabmap/LoopThr", which==0?"1":mLoopThrValues[which]) != 0)
00933                                 {
00934                                         mToast.makeText(getActivity(), "Failed to set parameter \"Rtabmap/LoopThr\"!", mToast.LENGTH_LONG).show();
00935                                 }
00936                         }
00937                     }
00938                   });
00939                   builder.show();
00940       }
00941       else if(itemId == R.id.optimize_error)
00942       {
00943           // get double
00944                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
00945                   builder.setTitle("Max Optimization Error (m)");
00946                   builder.setSingleChoiceItems(mOptimizeErrorValues, mParamOptimizeErrorIndex, new DialogInterface.OnClickListener() {
00947                     @Override
00948                     public void onClick(DialogInterface dialog, int which) {
00949                         dialog.dismiss();
00950                         if(which >=0 && which < mOptimizeErrorValues.length)
00951                         {
00952                                 mParamOptimizeErrorIndex = which;
00953                                 if(RTABMapLib.setMappingParameter("RGBD/OptimizeMaxError", which==0?"0":mOptimizeErrorValues[which]) != 0)
00954                                 {
00955                                         mToast.makeText(getActivity(), "Failed to set parameter \"RGBD/OptimizeMaxError\"!", mToast.LENGTH_LONG).show();
00956                                 }
00957                         }
00958                     }
00959                   });
00960                   builder.show();
00961       }
00962       else if (itemId == R.id.save)
00963       {
00964           if(mOpenedDatabasePath.isEmpty())
00965           {
00966                           AlertDialog.Builder builder = new AlertDialog.Builder(this);
00967                           builder.setTitle("RTAB-Map Database Name (*.db):");
00968                           final EditText input = new EditText(this);
00969                           input.setInputType(InputType.TYPE_CLASS_TEXT);        
00970                           builder.setView(input);
00971                           builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
00972                                   @Override
00973                                   public void onClick(DialogInterface dialog, int which)
00974                                   {
00975                                           final String fileName = input.getText().toString();  
00976                                           dialog.dismiss();
00977                                           if(!fileName.isEmpty())
00978                                           {
00979                                                   File newFile = new File(mWorkingDirectory + fileName + ".db");
00980                                                   if(newFile.exists())
00981                                                   {
00982                                                           new AlertDialog.Builder(getActivity())
00983                                                 .setTitle("File Already Exists")
00984                                                 .setMessage("Do you want to overwrite the existing file?")
00985                                                 .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
00986                                                     public void onClick(DialogInterface dialog, int which) {
00987                                                         mNewDatabasePath = mWorkingDirectory + fileName + ".db";
00988                                                         
00989                                                         mProgressDialog.setTitle("Saving");
00990                                                             mProgressDialog.setMessage(String.format("Please wait while saving \"%s\"...", mNewDatabasePath));
00991                                                             mProgressDialog.show();
00992                                                         
00993                                                                                 RTABMapLib.save(); // send save event
00994                                                                                 //disable gui actions
00995                                                                                 mItemSave.setEnabled(false);
00996                                                                                 mItemOpen.setEnabled(false);
00997                                                                                 mItemPostProcessing.setEnabled(false);
00998                                                                                 mItemExport.setEnabled(false);
00999                                                     }
01000                                                 })
01001                                                 .setNegativeButton("No", new DialogInterface.OnClickListener() {
01002                                                     public void onClick(DialogInterface dialog, int which) {
01003                                                         dialog.dismiss();
01004                                                     }
01005                                                 })
01006                                                 .show();
01007                                                   }
01008                                                   else
01009                                                   {
01010                                                           mNewDatabasePath = mWorkingDirectory + fileName + ".db";
01011                                                           
01012                                                           mProgressDialog.setTitle("Saving");
01013                                                   mProgressDialog.setMessage(String.format("Please wait while saving \"%s\"...", mNewDatabasePath));
01014                                                   mProgressDialog.show();
01015                                                           
01016                                                           RTABMapLib.save(); // send save event
01017                                                           //disable gui actions
01018                                                           mItemSave.setEnabled(false);
01019                                                           mItemOpen.setEnabled(false);
01020                                                           mItemPostProcessing.setEnabled(false);
01021                                                           mItemExport.setEnabled(false);
01022                                                   }
01023                                           }
01024                                   }
01025                           });
01026                           builder.show();
01027           }
01028           else
01029           {
01030                   mProgressDialog.setTitle("Saving");
01031                   mProgressDialog.setMessage(String.format("Please wait while updating \"%s\"...", mOpenedDatabasePath));
01032                   mProgressDialog.show();
01033                   
01034                   RTABMapLib.save(); // send save event
01035                   //disable gui actions
01036                           mItemSave.setEnabled(false);
01037                           mItemOpen.setEnabled(false);
01038                           mItemPostProcessing.setEnabled(false);
01039                           mItemExport.setEnabled(false);
01040           }
01041       }
01042       else if(itemId == R.id.reset)
01043       {
01044           ((TextView)findViewById(R.id.points)).setText(String.valueOf(0));
01045           ((TextView)findViewById(R.id.polygons)).setText(String.valueOf(0));
01046           ((TextView)findViewById(R.id.nodes)).setText(String.valueOf(0));
01047           ((TextView)findViewById(R.id.words)).setText(String.valueOf(0));
01048           ((TextView)findViewById(R.id.memory)).setText(String.valueOf(Debug.getNativeHeapAllocatedSize()/(1024*1024)));
01049           ((TextView)findViewById(R.id.db_size)).setText(String.valueOf(0));
01050           ((TextView)findViewById(R.id.inliers)).setText(String.valueOf(0));
01051           ((TextView)findViewById(R.id.features)).setText(String.valueOf(0));
01052           ((TextView)findViewById(R.id.update_time)).setText(String.valueOf(0));
01053           ((TextView)findViewById(R.id.hypothesis)).setText(String.valueOf(0));
01054           ((TextView)findViewById(R.id.fps)).setText(String.valueOf(0));
01055                   mTotalLoopClosures = 0;
01056                   ((TextView)findViewById(R.id.total_loop)).setText(String.valueOf(mTotalLoopClosures));
01057           
01058                   if(mOpenedDatabasePath.isEmpty())
01059                   {
01060                           RTABMapLib.resetMapping();
01061                   }
01062                   else
01063                   {
01064                           mOpenedDatabasePath = "";
01065                   RTABMapLib.openDatabase(mTempDatabasePath);
01066                   }
01067       }
01068       else if(itemId == R.id.export_obj || itemId == R.id.export_ply)
01069       {
01070           final String extension = itemId == R.id.export_ply ? ".ply" : ".obj";
01071           final boolean isOBJ = itemId == R.id.export_obj;
01072           
01073           final int polygons = Integer.parseInt(((TextView)findViewById(R.id.polygons)).getText().toString());
01074           
01075           AlertDialog.Builder builder = new AlertDialog.Builder(this);
01076                   builder.setTitle(String.format("File Name (*%s):", extension));
01077                   final EditText input = new EditText(this);
01078                   input.setInputType(InputType.TYPE_CLASS_TEXT);        
01079                   builder.setView(input);
01080                   builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
01081                           @Override
01082                           public void onClick(DialogInterface dialog, int which)
01083                           {
01084                                   final String fileName = input.getText().toString();    
01085                                   dialog.dismiss();
01086                                   if(!fileName.isEmpty())
01087                                   {
01088                                           File newFile = new File(mWorkingDirectory + fileName + extension);
01089                                           if(newFile.exists())
01090                                           {
01091                                                   new AlertDialog.Builder(getActivity())
01092                                         .setTitle("File Already Exists")
01093                                         .setMessage("Do you want to overwrite the existing file?")
01094                                         .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
01095                                             public void onClick(DialogInterface dialog, int which) {
01096                                                 final String path = mWorkingDirectory + fileName + extension;
01097                                                 
01098                                                 mItemExport.setEnabled(false);
01099                                                                                         
01100                                                 mProgressDialog.setTitle("Exporting");
01101                                                 if(polygons > 1000000)
01102                                                 {
01103                                                         mProgressDialog.setMessage(String.format(
01104                                                                         "Please wait while exporting \"%s\"...\n"
01105                                                                         + "Tip: With more than 1M polygons, to reduce exporting time and file size, consider:\n"
01106                                                                         + " a) increasing triangle size (Rendering options)\n"
01107                                                                         + " b) decreasing maximum camera depth (Rendering options)\n"
01108                                                                         + " c) activate Nodes Filtering (Mapping options)\n"
01109                                                                         + "then save/open to refresh the meshes.", fileName+extension));
01110                                                 }
01111                                                 else
01112                                                 {
01113                                                         mProgressDialog.setMessage(String.format("Please wait while exporting \"%s\"...", fileName+extension));
01114                                                 }
01115                                                     
01116                                                     mProgressDialog.show();
01117                                                   
01118                                                 Thread exportThread = new Thread(new Runnable() {
01119                                                             public void run() {
01120                                                                 final boolean success = RTABMapLib.exportMesh(path);
01121                                                                 runOnUiThread(new Runnable() {
01122                                                                         public void run() {
01123                                                                                 if(success)
01124                                                                                 {
01125                                                                                         if(isOBJ)
01126                                                                                         {       
01127                                                                                                 mToast.makeText(getActivity(), String.format("Mesh \"%s\" (with textures \"%s/\" and \"%s\") successfully exported!", path, fileName, fileName + ".mtl"), mToast.LENGTH_LONG).show();
01128                                                                                         }
01129                                                                                         else
01130                                                                                         {
01131                                                                                                 mToast.makeText(getActivity(), String.format("Mesh \"%s\" successfully exported!", path), mToast.LENGTH_LONG).show();
01132                                                                                         }
01133                                                                                 }
01134                                                                                 else
01135                                                                                 {
01136                                                                                         mToast.makeText(getActivity(), String.format("Exporting mesh to \"%s\" failed!", path), mToast.LENGTH_LONG).show();
01137                                                                                 }
01138                                                                                 mItemExport.setEnabled(true);
01139                                                                                 mProgressDialog.dismiss();
01140                                                                         }
01141                                                                 });
01142                                                             } 
01143                                                         });
01144                                                         exportThread.start();
01145                                             }
01146                                         })
01147                                         .setNegativeButton("No", new DialogInterface.OnClickListener() {
01148                                             public void onClick(DialogInterface dialog, int which) {
01149                                                 dialog.dismiss();
01150                                             }
01151                                         })
01152                                         .show();
01153                                           }
01154                                           else
01155                                           {
01156                                                   final String path = mWorkingDirectory + fileName + extension;
01157                                                   mItemExport.setEnabled(false);
01158                                                   mProgressDialog.setTitle("Exporting");
01159                                   mProgressDialog.setMessage(String.format("Please wait while exporting \"%s\"...", fileName+extension));
01160                                   mProgressDialog.show();
01161                                                   Thread exportThread = new Thread(new Runnable() {
01162                                             public void run() {
01163                                                 final boolean success = RTABMapLib.exportMesh(path);
01164                                                 runOnUiThread(new Runnable() {
01165                                                         public void run() {
01166                                                                 if(success)
01167                                                                 {
01168                                                                         if(isOBJ)
01169                                                                         {       
01170                                                                                 mToast.makeText(getActivity(), String.format("Mesh \"%s\" (with textures \"%s/\" and \"%s\") successfully exported!", path, fileName, fileName + ".mtl"), mToast.LENGTH_LONG).show();
01171                                                                         }
01172                                                                         else
01173                                                                         {
01174                                                                                 mToast.makeText(getActivity(), String.format("Mesh \"%s\" successfully exported!", path), mToast.LENGTH_LONG).show();
01175                                                                         }
01176                                                                 }
01177                                                                 else
01178                                                                 {
01179                                                                         mToast.makeText(getActivity(), String.format("Exporting mesh to \"%s\" failed!", path), mToast.LENGTH_LONG).show();
01180                                                                 }
01181                                                                 mItemExport.setEnabled(true);
01182                                                                 mProgressDialog.dismiss();
01183                                                         }
01184                                                 });
01185                                             } 
01186                                         });
01187                                         exportThread.start();
01188                                           }
01189                                   }
01190                           }
01191                   });
01192                   builder.show();
01193       }
01194       else if(itemId == R.id.open)
01195       {
01196           final String[] files = loadFileList(mWorkingDirectory);
01197           if(files.length > 0)
01198           {
01199                   AlertDialog.Builder builder = new AlertDialog.Builder(this);
01200                   builder.setTitle("Choose your file");
01201               builder.setItems(files, new DialogInterface.OnClickListener() {
01202                   public void onClick(DialogInterface dialog, int which) {
01203                           mOpenedDatabasePath = mWorkingDirectory + files[which];
01204                           
01205                           if(!mItemTrajectoryMode.isChecked())
01206                           {
01207                                   mProgressDialog.setTitle("Loading");
01208                                   mProgressDialog.setMessage(String.format("Database \"%s\" loaded. Please wait while creating point clouds and meshes...", files[which]));
01209                                   mProgressDialog.show();
01210                           }
01211 
01212                           RTABMapLib.openDatabase(mOpenedDatabasePath);
01213                           RTABMapLib.setCamera(1);
01214                           
01215                           File extStore = new File(mTempDatabasePath);
01216                           if(extStore.exists())
01217                           {
01218                           extStore.delete();
01219                           }  
01220                   }
01221               });
01222               builder.show();
01223           }     
01224       }
01225       else if(itemId == R.id.about)
01226       {
01227           AboutDialog about = new AboutDialog(this);
01228           about.setTitle("About RTAB-Map");
01229           about.show();
01230       }
01231 
01232       return true;
01233   }
01234 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Sat Jul 23 2016 11:44:17