mirror of
https://github.com/introlab/rtabmap.git
synced 2026-10-08 02:57:46 +08:00
Tango refactoring (#534)
* Created general CameraMobile interface. Tango is now optional. Camera is disabled on visualizaion (battery saving). * Working android app on non-tango android phones (tested on x86_64 android emulator). * fixed typo * android: updated tango not available msg * android: fixed build with latest android sdk/ndk * Added ARCore limited support for pose and rgb streams. * Added AREngine support. Don't assert if depth size is not a modulo of rgb size. * Added ARCore shared camera support * android: fixed read/write runtime permissions for >=api23. arcore ndk: added feature point cloud. Fixed file sharing persmissions (>=api24 issue) * ARCore NDK: mapping with feature point cloud * android: Added post build strip command to reduce native library size * android: fixed some compilation issues * android: put back gtsam as default optimizer, manifest min api is dynamic based on cmake parameters * AREngine: min api 24 * android: Fixed build without AREngine * android: fixed not available libraries for API<24 * android: fixed build with old cmake versions * android: set arcore min api to 23 * android: fixed arengine error on start when not built with native arengine support * android: fixed tango camera permission for api>=23 * Added bionic android docker files * Fixed wrong 3D words projection when depth size is not an exact multiple of rgb size. DbViewer: fixed images size not correctly shown in label of the calibration. ImageView: fixed depth scale when depth size is not a multiple of rgb size * CameraMobile: added exact display rotation for local transform * DbViewer: fixed gravity link shown in constraint view, show full local transform matrix in camera calibration label * Android: fixed localization mode in visualization, fixed some tansitions between some UI states * Android: Hide stop button when HUD is hidden. Updated About years.
This commit is contained in:
@@ -0,0 +1,556 @@
|
||||
package com.introlab.rtabmap;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.google.ar.core.Camera;
|
||||
import com.google.ar.core.CameraIntrinsics;
|
||||
import com.google.ar.core.Config;
|
||||
import com.google.ar.core.Frame;
|
||||
import com.google.ar.core.ImageMetadata;
|
||||
import com.google.ar.core.Pose;
|
||||
import com.google.ar.core.Session;
|
||||
import com.google.ar.core.SharedCamera;
|
||||
import com.google.ar.core.TrackingState;
|
||||
import com.google.ar.core.exceptions.CameraNotAvailableException;
|
||||
import com.google.ar.core.exceptions.NotYetAvailableException;
|
||||
import com.google.ar.core.exceptions.UnavailableException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.ImageFormat;
|
||||
import android.hardware.camera2.CameraAccessException;
|
||||
import android.hardware.camera2.CameraCaptureSession;
|
||||
import android.hardware.camera2.CameraCharacteristics;
|
||||
import android.hardware.camera2.CameraDevice;
|
||||
import android.hardware.camera2.CameraManager;
|
||||
import android.hardware.camera2.CaptureFailure;
|
||||
import android.hardware.camera2.CaptureRequest;
|
||||
import android.hardware.camera2.TotalCaptureResult;
|
||||
import android.media.Image;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
public class ARCoreSharedCamera {
|
||||
|
||||
public static final String TAG = ARCoreSharedCamera.class.getSimpleName();
|
||||
|
||||
|
||||
private static RTABMapActivity mActivity;
|
||||
public ARCoreSharedCamera(RTABMapActivity c) {
|
||||
mActivity = c;
|
||||
}
|
||||
|
||||
// Depth TOF Image.
|
||||
// Use 240 * 180 for now, hardcoded for Huawei P30 Pro
|
||||
private static final int DEPTH_WIDTH = 240;
|
||||
private static final int DEPTH_HEIGHT = 180;
|
||||
|
||||
// GL Surface used to draw camera preview image.
|
||||
public GLSurfaceView surfaceView;
|
||||
|
||||
// ARCore session that supports camera sharing.
|
||||
private Session sharedSession;
|
||||
|
||||
// Camera capture session. Used by both non-AR and AR modes.
|
||||
private CameraCaptureSession captureSession;
|
||||
|
||||
// Reference to the camera system service.
|
||||
private CameraManager cameraManager;
|
||||
|
||||
// Camera device. Used by both non-AR and AR modes.
|
||||
private CameraDevice cameraDevice;
|
||||
|
||||
// Looper handler thread.
|
||||
private HandlerThread backgroundThread;
|
||||
// Looper handler.
|
||||
private Handler backgroundHandler;
|
||||
|
||||
// ARCore shared camera instance, obtained from ARCore session that supports sharing.
|
||||
private SharedCamera sharedCamera;
|
||||
|
||||
// Camera ID for the camera used by ARCore.
|
||||
private String cameraId;
|
||||
|
||||
private AtomicBoolean mReady = new AtomicBoolean(false);
|
||||
|
||||
// Camera preview capture request builder
|
||||
private CaptureRequest.Builder previewCaptureRequestBuilder;
|
||||
|
||||
private int cameraTextureId = -1;
|
||||
|
||||
// Image reader that continuously processes CPU images.
|
||||
public TOF_ImageReader mTOFImageReader = new TOF_ImageReader();
|
||||
private boolean mTOFAvailable = false;
|
||||
|
||||
// Camera device state callback.
|
||||
private final CameraDevice.StateCallback cameraDeviceCallback =
|
||||
new CameraDevice.StateCallback() {
|
||||
@Override
|
||||
public void onOpened(@NonNull CameraDevice cameraDevice) {
|
||||
Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " opened.");
|
||||
ARCoreSharedCamera.this.cameraDevice = cameraDevice;
|
||||
createCameraPreviewSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(@NonNull CameraDevice cameraDevice) {
|
||||
Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " closed.");
|
||||
ARCoreSharedCamera.this.cameraDevice = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
|
||||
Log.w(TAG, "Camera device ID " + cameraDevice.getId() + " disconnected.");
|
||||
cameraDevice.close();
|
||||
ARCoreSharedCamera.this.cameraDevice = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull CameraDevice cameraDevice, int error) {
|
||||
Log.e(TAG, "Camera device ID " + cameraDevice.getId() + " error " + error);
|
||||
cameraDevice.close();
|
||||
ARCoreSharedCamera.this.cameraDevice = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Repeating camera capture session state callback.
|
||||
CameraCaptureSession.StateCallback cameraCaptureCallback =
|
||||
new CameraCaptureSession.StateCallback() {
|
||||
|
||||
// Called when the camera capture session is first configured after the app
|
||||
// is initialized, and again each time the activity is resumed.
|
||||
@Override
|
||||
public void onConfigured(@NonNull CameraCaptureSession session) {
|
||||
Log.d(TAG, "Camera capture session configured.");
|
||||
captureSession = session;
|
||||
setRepeatingCaptureRequest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfacePrepared(
|
||||
@NonNull CameraCaptureSession session, @NonNull Surface surface) {
|
||||
Log.d(TAG, "Camera capture surface prepared.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReady(@NonNull CameraCaptureSession session) {
|
||||
Log.d(TAG, "Camera capture session ready.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActive(@NonNull CameraCaptureSession session) {
|
||||
Log.d(TAG, "Camera capture session active.");
|
||||
resumeARCore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(@NonNull CameraCaptureSession session) {
|
||||
Log.d(TAG, "Camera capture session closed.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
|
||||
Log.e(TAG, "Failed to configure camera capture session.");
|
||||
}
|
||||
};
|
||||
|
||||
// Repeating camera capture session capture callback.
|
||||
private final CameraCaptureSession.CaptureCallback captureSessionCallback =
|
||||
new CameraCaptureSession.CaptureCallback() {
|
||||
|
||||
@Override
|
||||
public void onCaptureCompleted(
|
||||
@NonNull CameraCaptureSession session,
|
||||
@NonNull CaptureRequest request,
|
||||
@NonNull TotalCaptureResult result) {
|
||||
Log.i(TAG, "onCaptureCompleted");
|
||||
}
|
||||
|
||||
//@Override // android 23
|
||||
public void onCaptureBufferLost(
|
||||
@NonNull CameraCaptureSession session,
|
||||
@NonNull CaptureRequest request,
|
||||
@NonNull Surface target,
|
||||
long frameNumber) {
|
||||
Log.e(TAG, "onCaptureBufferLost: " + frameNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureFailed(
|
||||
@NonNull CameraCaptureSession session,
|
||||
@NonNull CaptureRequest request,
|
||||
@NonNull CaptureFailure failure) {
|
||||
Log.e(TAG, "onCaptureFailed: " + failure.getFrameNumber() + " " + failure.getReason());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCaptureSequenceAborted(
|
||||
@NonNull CameraCaptureSession session, int sequenceId) {
|
||||
Log.e(TAG, "onCaptureSequenceAborted: " + sequenceId + " " + session);
|
||||
}
|
||||
};
|
||||
|
||||
private void resumeARCore() {
|
||||
// Ensure that session is valid before triggering ARCore resume. Handles the case where the user
|
||||
// manually uninstalls ARCore while the app is paused and then resumes.
|
||||
if (sharedSession == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Resume ARCore.");
|
||||
// Resume ARCore.
|
||||
sharedSession.resume();
|
||||
// Set capture session callback while in AR mode.
|
||||
sharedCamera.setCaptureCallback(captureSessionCallback, backgroundHandler);
|
||||
} catch (CameraNotAvailableException e) {
|
||||
Log.e(TAG, "Failed to resume ARCore session", e);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Called when starting non-AR mode or switching to non-AR mode.
|
||||
// Also called when app starts in AR mode, or resumes in AR mode.
|
||||
private void setRepeatingCaptureRequest() {
|
||||
try {
|
||||
captureSession.setRepeatingRequest(
|
||||
previewCaptureRequestBuilder.build(), captureSessionCallback, backgroundHandler);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to set repeating request", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void createCameraPreviewSession() {
|
||||
Log.e(TAG, "createCameraPreviewSession: " + "starting camera preview session.");
|
||||
try {
|
||||
// Note that isGlAttached will be set to true in AR mode in onDrawFrame().
|
||||
sharedSession.setCameraTextureName(cameraTextureId);
|
||||
|
||||
// Create an ARCore compatible capture request using `TEMPLATE_RECORD`.
|
||||
previewCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
|
||||
|
||||
// Build surfaces list, starting with ARCore provided surfaces.
|
||||
List<Surface> surfaceList = sharedCamera.getArCoreSurfaces();
|
||||
Log.e(TAG, " createCameraPreviewSession: " + "surfaceList: sharedCamera.getArCoreSurfaces(): " + surfaceList.size());
|
||||
|
||||
// Add a CPU image reader surface. On devices that don't support CPU image access, the image
|
||||
// may arrive significantly later, or not arrive at all.
|
||||
if (mTOFAvailable) surfaceList.add(mTOFImageReader.imageReader.getSurface());
|
||||
// Surface list should now contain three surfacemReadymReadys:
|
||||
// 0. sharedCamera.getSurfaceTexture()
|
||||
// 1. …
|
||||
// 2. depthImageReader.getSurface()
|
||||
|
||||
// Add ARCore surfaces and CPU image surface targets.
|
||||
for (Surface surface : surfaceList) {
|
||||
previewCaptureRequestBuilder.addTarget(surface);
|
||||
}
|
||||
|
||||
// Wrap our callback in a shared camera callback.
|
||||
CameraCaptureSession.StateCallback wrappedCallback = sharedCamera.createARSessionStateCallback(cameraCaptureCallback, backgroundHandler);
|
||||
|
||||
// Create camera capture session for camera preview using ARCore wrapped callback.
|
||||
cameraDevice.createCaptureSession(surfaceList, wrappedCallback, backgroundHandler);
|
||||
|
||||
mReady.set(true);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "CameraAccessException", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Start background handler thread, used to run callbacks without blocking UI thread.
|
||||
private void startBackgroundThread() {
|
||||
backgroundThread = new HandlerThread("sharedCameraBackground");
|
||||
backgroundThread.start();
|
||||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
mTOFImageReader.startBackgroundThread();
|
||||
}
|
||||
|
||||
// Stop background handler thread.
|
||||
private void stopBackgroundThread() {
|
||||
if (backgroundThread != null) {
|
||||
backgroundThread.quitSafely();
|
||||
try {
|
||||
backgroundThread.join();
|
||||
backgroundThread = null;
|
||||
backgroundHandler = null;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while trying to join background handler thread", e);
|
||||
}
|
||||
}
|
||||
mTOFImageReader.stopBackgroundThread();
|
||||
}
|
||||
|
||||
private long mPreviousTime = 0;
|
||||
|
||||
// Perform various checks, then open camera device and create CPU image reader.
|
||||
public boolean openCamera() {
|
||||
|
||||
close();
|
||||
|
||||
startBackgroundThread();
|
||||
|
||||
mPreviousTime = System.currentTimeMillis();
|
||||
|
||||
if(cameraTextureId == -1)
|
||||
{
|
||||
int[] textures = new int[1];
|
||||
GLES20.glGenTextures(1, textures, 0);
|
||||
cameraTextureId = textures[0];
|
||||
}
|
||||
|
||||
Log.v(TAG + " opencamera: ", "Perform various checks, then open camera device and create CPU image reader.");
|
||||
// Don't open camera if already opened.
|
||||
if (cameraDevice != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sharedSession == null) {
|
||||
try {
|
||||
// Create ARCore session that supports camera sharing.
|
||||
sharedSession = new Session(mActivity, EnumSet.of(Session.Feature.SHARED_CAMERA));
|
||||
} catch (UnavailableException e) {
|
||||
Log.e(TAG, "Failed to create ARCore session that supports camera sharing", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable auto focus mode while ARCore is running.
|
||||
Config config = sharedSession.getConfig();
|
||||
config.setFocusMode(Config.FocusMode.AUTO);
|
||||
config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
|
||||
config.setPlaneFindingMode(Config.PlaneFindingMode.HORIZONTAL_AND_VERTICAL);
|
||||
config.setLightEstimationMode(Config.LightEstimationMode.DISABLED);
|
||||
config.setCloudAnchorMode(Config.CloudAnchorMode.ENABLED);
|
||||
sharedSession.configure(config);
|
||||
|
||||
}
|
||||
|
||||
// Store the ARCore shared camera reference.
|
||||
sharedCamera = sharedSession.getSharedCamera();
|
||||
// Store the ID of the camera used by ARCore.
|
||||
cameraId = sharedSession.getCameraConfig().getCameraId();
|
||||
initCamera(mActivity, cameraId, 1);
|
||||
ArrayList<String> resolutions;
|
||||
|
||||
mTOFAvailable = false;
|
||||
|
||||
resolutions = getResolutions(mActivity, cameraId, ImageFormat.DEPTH16);
|
||||
if (resolutions != null) {
|
||||
for( String temp : resolutions) {
|
||||
Log.v(TAG + "DEPTH16 resolution: ", temp);
|
||||
};
|
||||
if (resolutions.size() > 0) mTOFAvailable = true;
|
||||
}
|
||||
|
||||
// Color CPU Image.
|
||||
// Use the currently configured CPU image size.
|
||||
//Size desiredCPUImageSize = sharedSession.getCameraConfig().getImageSize();
|
||||
|
||||
if (mTOFAvailable) mTOFImageReader.createImageReader(DEPTH_WIDTH, DEPTH_HEIGHT);
|
||||
|
||||
// When ARCore is running, make sure it also updates our CPU image surface.
|
||||
if (mTOFAvailable) {
|
||||
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(mTOFImageReader.imageReader.getSurface()));
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Wrap our callback in a shared camera callback.
|
||||
CameraDevice.StateCallback wrappedCallback = sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler);
|
||||
|
||||
// Store a reference to the camera system service.
|
||||
cameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
|
||||
|
||||
// Get the characteristics for the ARCore camera.
|
||||
//CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(this.cameraId);
|
||||
|
||||
// Open the camera device using the ARCore wrapped callback.
|
||||
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler);
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to open camera", e);
|
||||
return false;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "Failed to open camera", e);
|
||||
return false;
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "Failed to open camera", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.i(TAG, " opencamera: TOF_available: " + mTOFAvailable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Close the camera device.
|
||||
public void close() {
|
||||
|
||||
if (sharedSession != null) {
|
||||
sharedSession.pause();
|
||||
}
|
||||
|
||||
if (captureSession != null) {
|
||||
captureSession.close();
|
||||
captureSession = null;
|
||||
}
|
||||
if (cameraDevice != null) {
|
||||
cameraDevice.close();
|
||||
}
|
||||
|
||||
if (mTOFImageReader.imageReader != null) {
|
||||
mTOFImageReader.imageReader.close();
|
||||
mTOFImageReader.imageReader = null;
|
||||
}
|
||||
|
||||
if(cameraTextureId>=0)
|
||||
{
|
||||
GLES20.glDeleteTextures(1, new int[] {cameraTextureId}, 0);
|
||||
}
|
||||
|
||||
stopBackgroundThread();
|
||||
}
|
||||
|
||||
/*************************************************** ONDRAWFRAME ARCORE ************************************************************* */
|
||||
|
||||
|
||||
// Draw frame when in AR mode. Called on the GL thread.
|
||||
public void updateGL() throws CameraNotAvailableException {
|
||||
|
||||
if(!mReady.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTOFAvailable && mTOFImageReader.frameCount == 0) return;
|
||||
|
||||
// Perform ARCore per-frame update.
|
||||
Frame frame = null;
|
||||
try {
|
||||
frame = sharedSession.update();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
Camera camera = null;
|
||||
if (frame != null) {
|
||||
camera = frame.getCamera();
|
||||
}else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == null) return;
|
||||
// If not tracking, don't draw 3D objects.
|
||||
if (camera.getTrackingState() == TrackingState.PAUSED) return;
|
||||
|
||||
if (frame.getTimestamp() != 0) {
|
||||
|
||||
Pose pose = camera.getPose();
|
||||
if(!mActivity.DISABLE_LOG) Log.d(TAG, String.format("pose=%f %f %f q=%f %f %f %f", pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw()));
|
||||
RTABMapLib.postCameraPoseEvent(mActivity.nativeApplication, pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw());
|
||||
|
||||
int rateMs = 100; // send images at most 10 Hz
|
||||
if(System. currentTimeMillis() - mPreviousTime < rateMs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mPreviousTime = System. currentTimeMillis();
|
||||
|
||||
CameraIntrinsics intrinsics = camera.getImageIntrinsics();
|
||||
try{
|
||||
Image image = frame.acquireCameraImage();
|
||||
|
||||
if (image.getFormat() != ImageFormat.YUV_420_888) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected image in YUV_420_888 format, got format " + image.getFormat());
|
||||
}
|
||||
|
||||
float[] fl = intrinsics.getFocalLength();
|
||||
float[] pp = intrinsics.getPrincipalPoint();
|
||||
if(!mActivity.DISABLE_LOG) Log.d(TAG, String.format("fx=%f fy=%f cx=%f cy=%f", fl[0], fl[1], pp[0], pp[1]));
|
||||
ByteBuffer rgb = image.getPlanes()[0].getBuffer().asReadOnlyBuffer();
|
||||
|
||||
double stamp = (double)image.getTimestamp()/10e8;
|
||||
if(!mActivity.DISABLE_LOG) Log.d(TAG, String.format("RGB %dx%d len=%dbytes format=%d =%f",
|
||||
image.getWidth(), image.getHeight(), rgb.limit(), image.getFormat(), stamp));
|
||||
if(!mActivity.DISABLE_LOG) Log.d(TAG, String.format("Depth %dx%d len=%dbytes format=%d stamp=%f",
|
||||
mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, mTOFImageReader.depth16_raw.limit(), ImageFormat.DEPTH16, (double)mTOFImageReader.timestamp/10e9));
|
||||
|
||||
RTABMapLib.postOdometryEvent(
|
||||
mActivity.nativeApplication,
|
||||
pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(),
|
||||
fl[0], fl[1], pp[0], pp[1], stamp,
|
||||
rgb, rgb.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
|
||||
mTOFImageReader.depth16_raw, mTOFImageReader.depth16_raw.limit(), mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, ImageFormat.DEPTH16);
|
||||
|
||||
|
||||
image.close();
|
||||
|
||||
} catch (NotYetAvailableException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************************************* */
|
||||
/*************************************************** End ************************************************************* */
|
||||
/********************************************************************************************************************* */
|
||||
|
||||
|
||||
public ArrayList<String> getResolutions (Context context, String cameraId,int imageFormat){
|
||||
Log.v(TAG + "getResolutions:", " cameraId:" + cameraId + " imageFormat: " + imageFormat);
|
||||
|
||||
ArrayList<String> output = new ArrayList<String>();
|
||||
try {
|
||||
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
||||
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
|
||||
|
||||
for (android.util.Size s : characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(imageFormat)) {
|
||||
output.add(s.getWidth() + "x" + s.getHeight());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
public void initCamera (Context context, String cameraId,int index){
|
||||
boolean ok = false;
|
||||
try {
|
||||
int current = 0;
|
||||
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
|
||||
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
|
||||
for (android.util.Size s : characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.DEPTH16)) {
|
||||
ok = true;
|
||||
if (current == index)
|
||||
break;
|
||||
else ;
|
||||
current++;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!ok) {
|
||||
Log.e(TAG + " initCamera", "Depth sensor not found!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.introlab.rtabmap;
|
||||
|
||||
import android.Manifest;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.provider.Settings;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
|
||||
/** Helper to ask camera permission. */
|
||||
public class PermissionHelper {
|
||||
public static final int CAMERA_CODE = 0;
|
||||
public static final int READ_EXTERNAL_STORAGE_CODE = 1;
|
||||
public static final int WRITE_EXTERNAL_STORAGE_CODE = 2;
|
||||
public static final int INTERNET_CODE = 3;
|
||||
public static final int ACCESS_NETWORK_STATE_CODE = 4;
|
||||
public static final int ACCESS_FINE_LOCATION_CODE = 5;
|
||||
public static final int ACCESS_WIFI_STATE_CODE = 6;
|
||||
|
||||
/** Check to see we have the necessary permissions for this app. */
|
||||
public static boolean hasPermission(Activity activity, String permission) {
|
||||
return ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
/** Check to see we have the necessary permissions for this app, and ask for them if we don't. */
|
||||
public static void requestPermission(Activity activity, String permission) {
|
||||
int requestCode = -1;
|
||||
if (permission == Manifest.permission.CAMERA) {
|
||||
requestCode = CAMERA_CODE;
|
||||
} else if(permission == Manifest.permission.READ_EXTERNAL_STORAGE) {
|
||||
requestCode = READ_EXTERNAL_STORAGE_CODE;
|
||||
} else if(permission == Manifest.permission.WRITE_EXTERNAL_STORAGE) {
|
||||
requestCode = WRITE_EXTERNAL_STORAGE_CODE;
|
||||
} else if(permission == Manifest.permission.INTERNET) {
|
||||
requestCode = INTERNET_CODE;
|
||||
} else if(permission == Manifest.permission.ACCESS_NETWORK_STATE) {
|
||||
requestCode = ACCESS_NETWORK_STATE_CODE;
|
||||
} else if(permission == Manifest.permission.ACCESS_FINE_LOCATION) {
|
||||
requestCode = ACCESS_FINE_LOCATION_CODE;
|
||||
} else if(permission == Manifest.permission.ACCESS_WIFI_STATE) {
|
||||
requestCode = ACCESS_WIFI_STATE_CODE;
|
||||
}
|
||||
if(requestCode >=0)
|
||||
{
|
||||
ActivityCompat.requestPermissions(
|
||||
activity, new String[] {permission}, requestCode);
|
||||
}
|
||||
}
|
||||
|
||||
/** Check to see if we need to show the rationale for this permission. */
|
||||
public static boolean shouldShowRequestPermissionRationale(Activity activity, String permission) {
|
||||
return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission);
|
||||
}
|
||||
|
||||
/** Launch Application Setting to grant permission. */
|
||||
public static void launchPermissionSettings(Activity activity) {
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
intent.setData(Uri.fromParts("package", activity.getPackageName(), null));
|
||||
activity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,9 @@
|
||||
|
||||
package com.introlab.rtabmap;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.IBinder;
|
||||
import android.view.KeyEvent;
|
||||
import android.util.Log;
|
||||
@@ -15,7 +19,7 @@ public class RTABMapLib
|
||||
// the correct library first.
|
||||
if (TangoInitializationHelper.loadTangoSharedLibrary() ==
|
||||
TangoInitializationHelper.ARCH_ERROR) {
|
||||
Log.e(RTABMapActivity.class.getSimpleName(), "ERROR! Unable to load libtango_client_api.so!");
|
||||
Log.w(RTABMapActivity.class.getSimpleName(), "WArning! Unable to load libtango_client_api.so! This can be safely ignored if RTAB-Map NDK is not build with tango support.");
|
||||
}
|
||||
System.loadLibrary("NativeRTABMap");
|
||||
}
|
||||
@@ -23,88 +27,89 @@ public class RTABMapLib
|
||||
// Initialize the Tango Service, this function starts the communication
|
||||
// between the application and Tango Service.
|
||||
// The activity object is used for checking if the API version is outdated.
|
||||
public static native void onCreate(RTABMapActivity activity);
|
||||
public static native long createNativeApplication(RTABMapActivity activity);
|
||||
|
||||
public static native void setScreenRotation(int displayRotation, int cameraRotation);
|
||||
public static native void destroyNativeApplication(long nativeApplication);
|
||||
|
||||
public static native int openDatabase(String databasePath, boolean databaseInMemory, boolean optimize);
|
||||
public static native int openDatabase2(String databaseSource, String databasePath, boolean databaseInMemory, boolean optimize);
|
||||
public static native void setScreenRotation(long nativeApplication, int displayRotation, int cameraRotation);
|
||||
|
||||
public static native int openDatabase(long nativeApplication, String databasePath, boolean databaseInMemory, boolean optimize);
|
||||
public static native int openDatabase2(long nativeApplication, String databaseSource, String databasePath, boolean databaseInMemory, boolean optimize);
|
||||
|
||||
/*
|
||||
* Called when the Tango service is connected.
|
||||
* Called when the camera service is connected.
|
||||
*
|
||||
* @param binder The native binder object.
|
||||
*/
|
||||
public static native boolean onTangoServiceConnected(IBinder binder);
|
||||
public static native boolean startCamera(long nativeApplication, IBinder binder, Context context, Activity activity, int driver);
|
||||
|
||||
// Release all non OpenGl resources that are allocated from the program.
|
||||
public static native void onPause();
|
||||
public static native void stopCamera(long nativeApplication);
|
||||
|
||||
// Allocate OpenGL resources for rendering.
|
||||
public static native void initGlContent();
|
||||
public static native void initGlContent(long nativeApplication);
|
||||
|
||||
// Setup the view port width and height.
|
||||
public static native void setupGraphic(int width, int height);
|
||||
public static native void setupGraphic(long nativeApplication, int width, int height);
|
||||
|
||||
// Main render loop.
|
||||
public static native int render();
|
||||
public static native int render(long nativeApplication);
|
||||
|
||||
// Set the render camera's viewing angle:
|
||||
// first person, third person, or top down.
|
||||
public static native void setCamera(int cameraIndex);
|
||||
public static native void setCamera(long nativeApplication, int cameraIndex);
|
||||
|
||||
// Pass touch events to the native layer.
|
||||
public static native void onTouchEvent(int touchCount, int event0,
|
||||
public static native void onTouchEvent(long nativeApplication, int touchCount, int event0,
|
||||
float x0, float y0, float x1, float y1);
|
||||
|
||||
|
||||
public static native void setPausedMapping(boolean paused);
|
||||
public static native void setOnlineBlending(boolean enabled);
|
||||
public static native void setMapCloudShown(boolean shown);
|
||||
public static native void setOdomCloudShown(boolean shown);
|
||||
public static native void setMeshRendering(boolean enabled, boolean withTexture);
|
||||
public static native void setLocalizationMode(boolean enabled);
|
||||
public static native void setTrajectoryMode(boolean enabled);
|
||||
public static native void setGraphOptimization(boolean enabled);
|
||||
public static native void setNodesFiltering(boolean enabled);
|
||||
public static native void setGraphVisible(boolean visible);
|
||||
public static native void setGridVisible(boolean visible);
|
||||
public static native void setRawScanSaved(boolean enabled);
|
||||
public static native void setFullResolution(boolean enabled);
|
||||
public static native void setSmoothing(boolean enabled);
|
||||
public static native void setCameraColor(boolean enabled);
|
||||
public static native void setAppendMode(boolean enabled);
|
||||
public static native void setDataRecorderMode(boolean enabled);
|
||||
public static native void setMaxCloudDepth(float value);
|
||||
public static native void setMinCloudDepth(float value);
|
||||
public static native void setPointSize(float value);
|
||||
public static native void setFOV(float value);
|
||||
public static native void setOrthoCropFactor(float value);
|
||||
public static native void setGridRotation(float value);
|
||||
public static native void setLighting(boolean enabled);
|
||||
public static native void setBackfaceCulling(boolean enabled);
|
||||
public static native void setWireframe(boolean enabled);
|
||||
public static native void setCloudDensityLevel(int value);
|
||||
public static native void setMeshAngleTolerance(float value);
|
||||
public static native void setMeshTriangleSize(int value);
|
||||
public static native void setClusterRatio(float value);
|
||||
public static native void setMaxGainRadius(float value);
|
||||
public static native void setRenderingTextureDecimation(int value);
|
||||
public static native void setBackgroundColor(float gray);
|
||||
public static native int setMappingParameter(String key, String value);
|
||||
public static native void setPausedMapping(long nativeApplication, boolean paused);
|
||||
public static native void setOnlineBlending(long nativeApplication, boolean enabled);
|
||||
public static native void setMapCloudShown(long nativeApplication, boolean shown);
|
||||
public static native void setOdomCloudShown(long nativeApplication, boolean shown);
|
||||
public static native void setMeshRendering(long nativeApplication, boolean enabled, boolean withTexture);
|
||||
public static native void setLocalizationMode(long nativeApplication, boolean enabled);
|
||||
public static native void setTrajectoryMode(long nativeApplication, boolean enabled);
|
||||
public static native void setGraphOptimization(long nativeApplication, boolean enabled);
|
||||
public static native void setNodesFiltering(long nativeApplication, boolean enabled);
|
||||
public static native void setGraphVisible(long nativeApplication, boolean visible);
|
||||
public static native void setGridVisible(long nativeApplication, boolean visible);
|
||||
public static native void setRawScanSaved(long nativeApplication, boolean enabled);
|
||||
public static native void setFullResolution(long nativeApplication, boolean enabled);
|
||||
public static native void setSmoothing(long nativeApplication, boolean enabled);
|
||||
public static native void setCameraColor(long nativeApplication, boolean enabled);
|
||||
public static native void setAppendMode(long nativeApplication, boolean enabled);
|
||||
public static native void setDataRecorderMode(long nativeApplication, boolean enabled);
|
||||
public static native void setMaxCloudDepth(long nativeApplication, float value);
|
||||
public static native void setMinCloudDepth(long nativeApplication, float value);
|
||||
public static native void setPointSize(long nativeApplication, float value);
|
||||
public static native void setFOV(long nativeApplication, float value);
|
||||
public static native void setOrthoCropFactor(long nativeApplication, float value);
|
||||
public static native void setGridRotation(long nativeApplication, float value);
|
||||
public static native void setLighting(long nativeApplication, boolean enabled);
|
||||
public static native void setBackfaceCulling(long nativeApplication, boolean enabled);
|
||||
public static native void setWireframe(long nativeApplication, boolean enabled);
|
||||
public static native void setCloudDensityLevel(long nativeApplication, int value);
|
||||
public static native void setMeshAngleTolerance(long nativeApplication, float value);
|
||||
public static native void setMeshTriangleSize(long nativeApplication, int value);
|
||||
public static native void setClusterRatio(long nativeApplication, float value);
|
||||
public static native void setMaxGainRadius(long nativeApplication, float value);
|
||||
public static native void setRenderingTextureDecimation(long nativeApplication, int value);
|
||||
public static native void setBackgroundColor(long nativeApplication, float gray);
|
||||
public static native int setMappingParameter(long nativeApplication, String key, String value);
|
||||
public static native void setGPS(
|
||||
long nativeApplication,
|
||||
double stamp,
|
||||
double longitude,
|
||||
double latitude,
|
||||
double altitude,
|
||||
double accuracy,
|
||||
double bearing);
|
||||
public static native void addEnvSensor(int type, float value);
|
||||
public static native void addEnvSensor(long nativeApplication, int type, float value);
|
||||
|
||||
public static native void resetMapping();
|
||||
public static native void save(String outputDatabasePath);
|
||||
public static native void cancelProcessing();
|
||||
public static native void save(long nativeApplication, String outputDatabasePath);
|
||||
public static native void cancelProcessing(long nativeApplication);
|
||||
public static native boolean exportMesh(
|
||||
long nativeApplication,
|
||||
float cloudVoxelSize,
|
||||
boolean regenerateCloud,
|
||||
boolean meshing,
|
||||
@@ -121,15 +126,23 @@ public class RTABMapLib
|
||||
float optimizedMaxTextureDistance,
|
||||
int optimizedMinTextureClusterSize,
|
||||
boolean blockRendering);
|
||||
public static native boolean writeExportedMesh(String directory, String name);
|
||||
public static native boolean postExportation(boolean visualize);
|
||||
public static native int postProcessing(int approach);
|
||||
public static native boolean writeExportedMesh(long nativeApplication, String directory, String name);
|
||||
public static native boolean postExportation(long nativeApplication, boolean visualize);
|
||||
public static native int postProcessing(long nativeApplication, int approach);
|
||||
|
||||
public static native String getStatus();
|
||||
public static native int getTotalNodes();
|
||||
public static native int getTotalWords();
|
||||
public static native int getTotalPoints();
|
||||
public static native float getUpdateTime();
|
||||
public static native int getLoopClosureId();
|
||||
public static native String getStatus(long nativeApplication);
|
||||
public static native int getTotalNodes(long nativeApplication);
|
||||
public static native int getTotalWords(long nativeApplication);
|
||||
public static native int getTotalPoints(long nativeApplication);
|
||||
public static native float getUpdateTime(long nativeApplication);
|
||||
public static native int getLoopClosureId(long nativeApplication);
|
||||
|
||||
public static native void postCameraPoseEvent(long nativeApplication, float x, float y, float z, float qx, float qy, float qz, float qw);
|
||||
public static native void postOdometryEvent(long nativeApplication,
|
||||
float x, float y, float z, float qx, float qy, float qz, float qw,
|
||||
float fx, float fy, float cx, float cy,
|
||||
double stamp,
|
||||
ByteBuffer rgb, int rgbLen, int rgbWidth, int rgbHeight, int rgbFormat,
|
||||
ByteBuffer depth, int depthLen, int depthWidth, int depthHeight, int depthFormat);
|
||||
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ public class Renderer implements GLSurfaceView.Renderer {
|
||||
private float mSurfaceHeight = 0.0f;
|
||||
private float mTextColor = 1.0f;
|
||||
private int mOffset = 0;
|
||||
private ARCoreSharedCamera mCamera = null;
|
||||
|
||||
private Vector<TextObject> mTexts;
|
||||
|
||||
@@ -71,91 +72,109 @@ public class Renderer implements GLSurfaceView.Renderer {
|
||||
{
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
public void setCamera(ARCoreSharedCamera camera)
|
||||
{
|
||||
mCamera = camera;
|
||||
}
|
||||
|
||||
// Render loop of the Gl context.
|
||||
public void onDrawFrame(GL10 useGLES20instead) {
|
||||
|
||||
try
|
||||
{
|
||||
final int value = RTABMapLib.render();
|
||||
|
||||
if(mTextManager!=null)
|
||||
synchronized (this) {
|
||||
if(mActivity.nativeApplication != 0)
|
||||
{
|
||||
if(mTextChanged)
|
||||
try
|
||||
{
|
||||
mTextChanged = false;
|
||||
Vector<TextObject> txtcollection = new Vector<TextObject>();
|
||||
|
||||
mTextLock.lock();
|
||||
try {
|
||||
if(mTexts.size() > 0)
|
||||
{
|
||||
txtcollection.addAll(mTexts);
|
||||
}
|
||||
} finally {
|
||||
mTextLock.unlock();
|
||||
}
|
||||
|
||||
// Prepare the text for rendering
|
||||
mTextManager.PrepareDraw(txtcollection);
|
||||
}
|
||||
|
||||
float[] mvp = new float[16];
|
||||
Matrix.translateM(mvp, 0, mtrxProjectionAndView, 0, 0, mOffset, 0);
|
||||
mTextManager.Draw(mvp);
|
||||
}
|
||||
|
||||
if(value != 0 && mProgressDialog != null && mProgressDialog.isShowing())
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(!RTABMapActivity.DISABLE_LOG) Log.i("RTABMapActivity", "Renderer: dismiss dialog, value received=" + String.valueOf(value));
|
||||
mProgressDialog.dismiss();
|
||||
mActivity.resetNoTouchTimer();
|
||||
}
|
||||
});
|
||||
}
|
||||
if(value==-1)
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(mToast!=null)
|
||||
{
|
||||
mToast.makeText(mActivity, String.format("Out of Memory!"), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(value==-2)
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(mToast!=null)
|
||||
{
|
||||
mToast.makeText(mActivity, String.format("Rendering Error!"), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
catch(final Exception e)
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(mToast!=null)
|
||||
if(mCamera!=null)
|
||||
{
|
||||
mToast.makeText(mActivity, String.format("Rendering error! %s", e.getMessage()), Toast.LENGTH_SHORT).show();
|
||||
mCamera.updateGL();
|
||||
}
|
||||
|
||||
final int value = RTABMapLib.render(mActivity.nativeApplication);
|
||||
|
||||
if(mTextManager!=null)
|
||||
{
|
||||
if(mTextChanged)
|
||||
{
|
||||
mTextChanged = false;
|
||||
Vector<TextObject> txtcollection = new Vector<TextObject>();
|
||||
|
||||
mTextLock.lock();
|
||||
try {
|
||||
if(mTexts.size() > 0)
|
||||
{
|
||||
txtcollection.addAll(mTexts);
|
||||
}
|
||||
} finally {
|
||||
mTextLock.unlock();
|
||||
}
|
||||
|
||||
// Prepare the text for rendering
|
||||
mTextManager.PrepareDraw(txtcollection);
|
||||
}
|
||||
|
||||
float[] mvp = new float[16];
|
||||
Matrix.translateM(mvp, 0, mtrxProjectionAndView, 0, 0, mOffset, 0);
|
||||
mTextManager.Draw(mvp);
|
||||
}
|
||||
|
||||
if(value != 0 && mProgressDialog != null && mProgressDialog.isShowing())
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(!RTABMapActivity.DISABLE_LOG) Log.i("RTABMapActivity", "Renderer: dismiss dialog, value received=" + String.valueOf(value));
|
||||
mProgressDialog.dismiss();
|
||||
mActivity.resetNoTouchTimer();
|
||||
}
|
||||
});
|
||||
}
|
||||
if(value==-1)
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(mToast!=null)
|
||||
{
|
||||
mToast.makeText(mActivity, String.format("Out of Memory!"), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if(value==-2)
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(mToast!=null)
|
||||
{
|
||||
mToast.makeText(mActivity, String.format("Rendering Error!"), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
catch(final Exception e)
|
||||
{
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
if(mToast!=null)
|
||||
{
|
||||
mToast.makeText(mActivity, String.format("Rendering error! %s", e.getMessage()), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the surface size changes.
|
||||
public void onSurfaceChanged(GL10 useGLES20instead, int width, int height) {
|
||||
|
||||
RTABMapLib.setupGraphic(width, height);
|
||||
if(mActivity.nativeApplication!=0)
|
||||
{
|
||||
RTABMapLib.setupGraphic(mActivity.nativeApplication, width, height);
|
||||
}
|
||||
|
||||
mSurfaceHeight = (float)height;
|
||||
|
||||
@@ -180,7 +199,10 @@ public class Renderer implements GLSurfaceView.Renderer {
|
||||
// Called when the surface is created or recreated.
|
||||
public void onSurfaceCreated(GL10 useGLES20instead, EGLConfig config) {
|
||||
|
||||
RTABMapLib.initGlContent();
|
||||
if(mActivity.nativeApplication != 0)
|
||||
{
|
||||
RTABMapLib.initGlContent(mActivity.nativeApplication);
|
||||
}
|
||||
|
||||
// Create our text manager
|
||||
mTextManager = new TextManager(mActivity);
|
||||
|
||||
@@ -7,11 +7,14 @@ import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
@@ -19,6 +22,7 @@ import android.text.InputType;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
|
||||
|
||||
@@ -34,7 +38,7 @@ public class SettingsActivity extends PreferenceActivity implements OnSharedPref
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
getPreferenceScreen().getSharedPreferences().edit().clear().commit();
|
||||
|
||||
|
||||
recreate();
|
||||
|
||||
return true;
|
||||
@@ -184,7 +188,31 @@ public class SettingsActivity extends PreferenceActivity implements OnSharedPref
|
||||
}
|
||||
});
|
||||
|
||||
Preference buttonGPS = findPreference(getString(R.string.pref_key_gps_saved));
|
||||
buttonGPS.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if(((CustomSwitchPreference)preference).isChecked())
|
||||
{
|
||||
if (!PermissionHelper.hasPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
((CustomSwitchPreference)preference).setChecked(false);
|
||||
PermissionHelper.requestPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if(((CustomSwitchPreference)buttonGPS).isChecked())
|
||||
{
|
||||
if (!PermissionHelper.hasPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
((CustomSwitchPreference)buttonGPS).setChecked(false);
|
||||
PermissionHelper.requestPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
((Preference)findPreference(getString(R.string.pref_key_camera_driver))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_camera_driver))).getEntry() + ") "+getString(R.string.pref_summary_camera_driver));
|
||||
((Preference)findPreference(getString(R.string.pref_key_density))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_density))).getEntry() + ") "+getString(R.string.pref_summary_density));
|
||||
((Preference)findPreference(getString(R.string.pref_key_depth))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_depth))).getEntry() + ") "+getString(R.string.pref_summary_depth));
|
||||
((Preference)findPreference(getString(R.string.pref_key_min_depth))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_min_depth))).getEntry() + ") "+getString(R.string.pref_summary_min_depth));
|
||||
@@ -228,6 +256,7 @@ public class SettingsActivity extends PreferenceActivity implements OnSharedPref
|
||||
Preference pref = findPreference(key);
|
||||
|
||||
if (pref instanceof ListPreference) {
|
||||
if(key.compareTo(getString(R.string.pref_key_camera_driver))==0) pref.setSummary("("+ ((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_camera_driver));
|
||||
if(key.compareTo(getString(R.string.pref_key_density))==0) pref.setSummary("("+ ((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_density));
|
||||
if(key.compareTo(getString(R.string.pref_key_depth))==0)
|
||||
{
|
||||
@@ -331,4 +360,28 @@ public class SettingsActivity extends PreferenceActivity implements OnSharedPref
|
||||
}
|
||||
ed.commit(); //save it.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
|
||||
|
||||
switch (requestCode) {
|
||||
case PermissionHelper.ACCESS_FINE_LOCATION_CODE: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
if (results.length > 0 && results[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// permission was granted, yay! Do the
|
||||
// contacts-related task you need to do.
|
||||
Preference buttonGPS = findPreference(getString(R.string.pref_key_gps_saved));
|
||||
((CustomSwitchPreference)buttonGPS).setChecked(true);
|
||||
} else {
|
||||
// permission denied, boo! Disable the
|
||||
// functionality that depends on this permission.
|
||||
Toast.makeText(this, "Location permission is needed to use GPS functionality", Toast.LENGTH_LONG).show();
|
||||
if (!PermissionHelper.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
PermissionHelper.launchPermissionSettings(this); // Permission denied with checking "Do not ask again".
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +245,7 @@ public class SketchfabActivity extends Activity implements OnClickListener {
|
||||
File exportDir = new File(mWorkingDirectory + RTABMapActivity.RTABMAP_EXPORT_DIR);
|
||||
exportDir.mkdirs();
|
||||
|
||||
if(RTABMapLib.writeExportedMesh(mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR, RTABMapActivity.RTABMAP_TMP_FILENAME))
|
||||
if(RTABMapLib.writeExportedMesh(RTABMapActivity.nativeApplication, mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR, RTABMapActivity.RTABMAP_TMP_FILENAME))
|
||||
{
|
||||
String[] files = new String[0];
|
||||
// verify if we have all files
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.introlab.rtabmap;
|
||||
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.media.Image;
|
||||
import android.media.ImageReader;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class TOF_ImageReader implements ImageReader.OnImageAvailableListener {
|
||||
|
||||
public int WIDTH;
|
||||
public int HEIGHT;
|
||||
public ImageReader imageReader;
|
||||
public int frameCount = 0;
|
||||
public long timestamp;
|
||||
|
||||
// Looper handler thread.
|
||||
private HandlerThread backgroundThread;
|
||||
// Looper handler.
|
||||
private Handler backgroundHandler;
|
||||
|
||||
public ByteBuffer depth16_raw;
|
||||
|
||||
TOF_ImageReader(){
|
||||
}
|
||||
|
||||
public void createImageReader(int width, int height){
|
||||
this.WIDTH = width;
|
||||
this.HEIGHT = height;
|
||||
this.imageReader =
|
||||
ImageReader.newInstance(
|
||||
width,
|
||||
height,
|
||||
ImageFormat.DEPTH16,
|
||||
2);
|
||||
this.imageReader.setOnImageAvailableListener(this, this.backgroundHandler);
|
||||
}
|
||||
|
||||
// CPU image reader callback.
|
||||
@Override
|
||||
public void onImageAvailable(ImageReader imageReader) {
|
||||
Image image = imageReader.acquireLatestImage();
|
||||
if (image == null) {
|
||||
Log.w("RTABMapActivity", "onImageAvailable: Skipping null image.");
|
||||
return;
|
||||
}
|
||||
else{
|
||||
if(image.getFormat() == ImageFormat.DEPTH16){
|
||||
this.timestamp = image.getTimestamp();
|
||||
depth16_raw = image.getPlanes()[0].getBuffer().asReadOnlyBuffer();
|
||||
// copy raw undecoded DEPTH16 format depth data to NativeBuffer
|
||||
frameCount++;
|
||||
}
|
||||
else{
|
||||
Log.w("RTABMapActivity", "onImageAvailable: depth image not in DEPTH16 format, skipping image");
|
||||
}
|
||||
}
|
||||
image.close();
|
||||
}
|
||||
|
||||
// Start background handler thread, used to run callbacks without blocking UI thread.
|
||||
public void startBackgroundThread() {
|
||||
this.backgroundThread = new HandlerThread("DepthDecoderThread");
|
||||
this.backgroundThread.start();
|
||||
this.backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
}
|
||||
|
||||
// Stop background handler thread.
|
||||
public void stopBackgroundThread() {
|
||||
if (this.backgroundThread != null) {
|
||||
this.backgroundThread.quitSafely();
|
||||
try {
|
||||
this.backgroundThread.join();
|
||||
this.backgroundThread = null;
|
||||
this.backgroundHandler = null;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("RTABMapActivity", "Interrupted while trying to join depth background handler thread", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.graphics.Typeface;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLUtils;
|
||||
import android.text.TextPaint;
|
||||
import android.util.Log;
|
||||
|
||||
public class TextManager {
|
||||
|
||||
@@ -336,6 +337,8 @@ public class TextManager {
|
||||
float y = val.y;
|
||||
String text = val.text;
|
||||
|
||||
Log.i("RTABMapActivity", String.format("convertTextToTriangleInfo() set status=%s", text));
|
||||
|
||||
// Create
|
||||
for(int j=0; j<text.length(); j++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user