diff --git a/AreaLearningJava/app/src/main/java/com/projecttango/experiments/javaarealearning/AreaLearningActivity.java b/AreaLearningJava/app/src/main/java/com/projecttango/experiments/javaarealearning/AreaLearningActivity.java index 4c804325..ae1e5e99 100644 --- a/AreaLearningJava/app/src/main/java/com/projecttango/experiments/javaarealearning/AreaLearningActivity.java +++ b/AreaLearningJava/app/src/main/java/com/projecttango/experiments/javaarealearning/AreaLearningActivity.java @@ -18,12 +18,10 @@ import com.google.atap.tangoservice.Tango.OnTangoUpdateListener; import com.google.atap.tangoservice.Tango; -import com.google.atap.tangoservice.TangoAreaDescriptionMetaData; import com.google.atap.tangoservice.TangoConfig; import com.google.atap.tangoservice.TangoCoordinateFramePair; import com.google.atap.tangoservice.TangoErrorException; import com.google.atap.tangoservice.TangoEvent; -import com.google.atap.tangoservice.TangoException; import com.google.atap.tangoservice.TangoInvalidException; import com.google.atap.tangoservice.TangoOutOfDateException; import com.google.atap.tangoservice.TangoPoseData; @@ -34,7 +32,6 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; -import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; @@ -43,14 +40,14 @@ import android.widget.TextView; import android.widget.Toast; -import java.text.DecimalFormat; -import java.util.ArrayList; - import com.projecttango.tangoutils.TangoPoseUtilities; import org.rajawali3d.surface.IRajawaliSurface; import org.rajawali3d.surface.RajawaliSurfaceView; +import java.text.DecimalFormat; +import java.util.ArrayList; + /** * Main Activity class for the Area Learning API Sample. Handles the connection to the Tango service * and propagation of Tango pose data to OpenGL and Layout views. OpenGL rendering logic is @@ -60,7 +57,7 @@ public class AreaLearningActivity extends Activity implements View.OnClickListen SetADFNameDialog.CallbackListener, SaveAdfTask.SaveAdfListener { private static final String TAG = AreaLearningActivity.class.getSimpleName(); - private static final int SECONDS_TO_MILLI = 1000; + private static final int SECS_TO_MILLISECS = 1000; private Tango mTango; private TangoConfig mConfig; private TextView mTangoEventTextView; @@ -102,6 +99,9 @@ public class AreaLearningActivity extends Activity implements View.OnClickListen private double mAdf2DevicePreviousPoseTimeStamp; private double mAdf2StartPreviousPoseTimeStamp; + private double mPreviousPoseTimeStamp; + private double mTimeToNextUpdate = UPDATE_INTERVAL_MS; + private boolean mIsRelocalized; private boolean mIsLearningMode; private boolean mIsConstantSpaceRelocalize; @@ -113,9 +113,10 @@ public class AreaLearningActivity extends Activity implements View.OnClickListen private SaveAdfTask mSaveAdfTask; private TangoPoseData[] mPoses; - private static final int UPDATE_INTERVAL_MS = 100; - private static final DecimalFormat mThreeDecimalFormat = new DecimalFormat("00.000"); - private static final Object mSharedLock = new Object(); + private static final double UPDATE_INTERVAL_MS = 100.0; + private static final DecimalFormat FORMAT_THREE_DECIMAL = new DecimalFormat("00.000"); + + private final Object mSharedLock = new Object(); @Override protected void onCreate(Bundle savedInstanceState) { @@ -140,8 +141,6 @@ protected void onCreate(Bundle savedInstanceState) { mStart2DevicePoseCount = 0; mAdf2DevicePoseCount = 0; mAdf2StartPoseCount = 0; - - startUIThread(); } /** @@ -405,7 +404,6 @@ public void onPoseAvailable(TangoPoseData pose) { // UI loop doesn't interfere while Pose call back is updating // the data. synchronized (mSharedLock) { - float[] translation = pose.getTranslationAsFloats(); // Check for Device wrt ADF pose, Device wrt Start of Service pose, // Start of Service wrt ADF pose(This pose determines if device // the is relocalized or not). @@ -421,7 +419,7 @@ public void onPoseAvailable(TangoPoseData pose) { // Calculate time difference between current and last available Device wrt // ADF pose. mAdf2DevicePoseDelta = (pose.timestamp - mAdf2DevicePreviousPoseTimeStamp) - * SECONDS_TO_MILLI; + * SECS_TO_MILLISECS; mAdf2DevicePreviousPoseTimeStamp = pose.timestamp; if (mIsRelocalized) { updateRenderer = true; @@ -438,7 +436,7 @@ public void onPoseAvailable(TangoPoseData pose) { // Calculate time difference between current and last available Device wrt // SS pose. mStart2DevicePoseDelta = (pose.timestamp - mStart2DevicePreviousPoseTimeStamp) - * SECONDS_TO_MILLI; + * SECS_TO_MILLISECS; mStart2DevicePreviousPoseTimeStamp = pose.timestamp; if (!mIsRelocalized) { updateRenderer = true; @@ -456,7 +454,7 @@ public void onPoseAvailable(TangoPoseData pose) { // Calculate time difference between current and last available SS wrt ADF // pose. mAdf2StartPoseDelta = (pose.timestamp - mAdf2StartPreviousPoseTimeStamp) - * SECONDS_TO_MILLI; + * SECS_TO_MILLISECS; mAdf2StartPreviousPoseTimeStamp = pose.timestamp; if (pose.statusCode == TangoPoseData.POSE_VALID) { mIsRelocalized = true; @@ -467,6 +465,24 @@ public void onPoseAvailable(TangoPoseData pose) { } } } + + final double deltaTime = (pose.timestamp - mPreviousPoseTimeStamp) * SECS_TO_MILLISECS; + mPreviousPoseTimeStamp = pose.timestamp; + mTimeToNextUpdate -= deltaTime; + + if (mTimeToNextUpdate < 0.0) { + mTimeToNextUpdate = UPDATE_INTERVAL_MS; + + runOnUiThread(new Runnable() { + @Override + public void run() { + synchronized (mSharedLock) { + updateTextViews(); + } + } + }); + } + if (updateRenderer) { mRenderer.updateDevicePose(pose, mIsRelocalized); } @@ -527,42 +543,6 @@ private void showSetADFNameDialog() { setADFNameDialog.show(manager, "ADFNameDialog"); } - /** - * Create a separate thread to update Log information on UI at the specified interval of - * UPDATE_INTERVAL_MS. This function also makes sure to have access to the mPoses atomically. - */ - private void startUIThread() { - new Thread(new Runnable() { - @Override - public void run() { - while (true) { - try { - Thread.sleep(UPDATE_INTERVAL_MS); - runOnUiThread(new Runnable() { - @Override - public void run() { - try { - synchronized (mSharedLock) { - - if (mPoses == null) { - return; - } else { - updateTextViews(); - } - } - } catch (NullPointerException e) { - e.printStackTrace(); - } - } - }); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - }).start(); - } - /** * Updates the text view in UI screen with the Pose. Each pose is associated with Target and * Base Frame. We need to check for that pair and update our views accordingly. @@ -571,34 +551,31 @@ private void updateTextViews() { // Allow clicking of the save button only when Tango is localized to the current ADF. mSaveAdfButton.setEnabled(mIsRelocalized); - if (mPoses[0] != null - && mPoses[0].baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION + if (mPoses[0] != null && mPoses[0].baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION && mPoses[0].targetFrame == TangoPoseData.COORDINATE_FRAME_DEVICE) { - mAdf2DeviceTranslationTextView.setText(TangoPoseUtilities.getTranslationString(mPoses[0], mThreeDecimalFormat)); - mAdf2DeviceQuatTextView.setText(TangoPoseUtilities.getQuaternionString(mPoses[0], mThreeDecimalFormat)); + mAdf2DeviceTranslationTextView.setText(TangoPoseUtilities.getTranslationString(mPoses[0], FORMAT_THREE_DECIMAL)); + mAdf2DeviceQuatTextView.setText(TangoPoseUtilities.getQuaternionString(mPoses[0], FORMAT_THREE_DECIMAL)); mAdf2DevicePoseStatusTextView.setText(TangoPoseUtilities.getStatusString(mPoses[0])); mAdf2DevicePoseCountTextView.setText(Integer.toString(mAdf2DevicePoseCount)); - mAdf2DevicePoseDeltaTextView.setText(mThreeDecimalFormat.format(mAdf2DevicePoseDelta)); + mAdf2DevicePoseDeltaTextView.setText(FORMAT_THREE_DECIMAL.format(mAdf2DevicePoseDelta)); } - if (mPoses[1] != null - && mPoses[1].baseFrame == TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE + if (mPoses[1] != null && mPoses[1].baseFrame == TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE && mPoses[1].targetFrame == TangoPoseData.COORDINATE_FRAME_DEVICE) { - mStart2DeviceTranslationTextView.setText(TangoPoseUtilities.getTranslationString(mPoses[1], mThreeDecimalFormat)); - mStart2DeviceQuatTextView.setText(TangoPoseUtilities.getQuaternionString(mPoses[1], mThreeDecimalFormat)); + mStart2DeviceTranslationTextView.setText(TangoPoseUtilities.getTranslationString(mPoses[1], FORMAT_THREE_DECIMAL)); + mStart2DeviceQuatTextView.setText(TangoPoseUtilities.getQuaternionString(mPoses[1], FORMAT_THREE_DECIMAL)); mStart2DevicePoseStatusTextView.setText(TangoPoseUtilities.getStatusString(mPoses[1])); mStart2DevicePoseCountTextView.setText(Integer.toString(mStart2DevicePoseCount)); - mStart2DevicePoseDeltaTextView.setText(mThreeDecimalFormat.format(mStart2DevicePoseDelta)); + mStart2DevicePoseDeltaTextView.setText(FORMAT_THREE_DECIMAL.format(mStart2DevicePoseDelta)); } - if (mPoses[2] != null - && mPoses[2].baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION + if (mPoses[2] != null && mPoses[2].baseFrame == TangoPoseData.COORDINATE_FRAME_AREA_DESCRIPTION && mPoses[2].targetFrame == TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE) { - mAdf2StartTranslationTextView.setText(TangoPoseUtilities.getTranslationString(mPoses[2], mThreeDecimalFormat)); - mAdf2StartQuatTextView.setText(TangoPoseUtilities.getQuaternionString(mPoses[2], mThreeDecimalFormat)); + mAdf2StartTranslationTextView.setText(TangoPoseUtilities.getTranslationString(mPoses[2], FORMAT_THREE_DECIMAL)); + mAdf2StartQuatTextView.setText(TangoPoseUtilities.getQuaternionString(mPoses[2], FORMAT_THREE_DECIMAL)); mAdf2StartPoseStatusTextView.setText(TangoPoseUtilities.getStatusString(mPoses[2])); mAdf2StartPoseCountTextView.setText(Integer.toString(mAdf2StartPoseCount)); - mAdf2StartPoseDeltaTextView.setText(mThreeDecimalFormat.format(mAdf2StartPoseDelta)); + mAdf2StartPoseDeltaTextView.setText(FORMAT_THREE_DECIMAL.format(mAdf2StartPoseDelta)); } } } diff --git a/AreaLearningJava/gradle/wrapper/gradle-wrapper.jar b/AreaLearningJava/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a..c97a8bdb 100644 Binary files a/AreaLearningJava/gradle/wrapper/gradle-wrapper.jar and b/AreaLearningJava/gradle/wrapper/gradle-wrapper.jar differ diff --git a/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityActivity.java b/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityActivity.java index d2f00123..4fb55ad5 100644 --- a/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityActivity.java +++ b/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityActivity.java @@ -13,10 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.projecttango.experiments.augmentedrealitysample; import android.app.Activity; -import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; @@ -33,39 +33,45 @@ import com.google.atap.tangoservice.TangoOutOfDateException; import com.google.atap.tangoservice.TangoPoseData; import com.google.atap.tangoservice.TangoXyzIjData; -import com.projecttango.rajawali.ar.TangoRajawaliView; -import com.projecttango.tangosupport.TangoSupport; import java.util.ArrayList; +import com.projecttango.rajawali.ar.TangoRajawaliView; +import com.projecttango.tangosupport.TangoPointCloudManager; +import com.projecttango.tangosupport.TangoSupport; +import com.projecttango.tangosupport.TangoSupport.IntersectionPointPlaneModelPair; + /** - * An example showing how to build a very simple augmented reality application in Java. - * It uses Rajawali to do the rendering through the utility classes - * TangoRajawaliRenderer and TangoRajawaliView from TangoUtils. - * It also uses the TangoSupportLibrary to do plane fitting using the PointCloud data. Whenever the - * user clicks on the camera display, plane detection will be done on the surface closest to the - * click location and a 3D object will be placed in the scene anchored in that location. + * An example showing how to build a very simple augmented reality application + * in Java. It uses Rajawali to do the rendering through the utility classes + * TangoRajawaliRenderer and TangoRajawaliView from + * TangoUtils. It also uses the TangoSupportLibrary to do plane fitting using + * the PointCloud data. Whenever the user clicks on the camera display, plane + * detection will be done on the surface closest to the click location and a 3D + * object will be placed in the scene anchored in that location. *

- * TangoRajawaliView is used in the same way as the TangoCameraPreview: We first need initialize the - * TangoRajawaliView class with the activity's context and connect to the camera we want by using - * connectToTangoCamera method. Once the connection is established we need to update - * the view's texture by using the onFrameAvailable callbacks. + * TangoRajawaliView is used in the same way as the TangoCameraPreview: We first + * need initialize the TangoRajawaliView class with the activity's context and + * connect to the camera we want by using connectToTangoCamera method. Once the + * connection is established we need to update the view's texture by using the + * onFrameAvailable callbacks. *

- * The TangoRajawaliRenderer class is used the same way as a RajawaliRenderer. We need to create it - * with a reference to the activity's context and then pass it to the view with the view's - * setSurfaceRenderer method. - * The implementation of the 3D world is done by subclassing the Renderer, just like any other + * The TangoRajawaliRenderer class is used the same way as a RajawaliRenderer. + * We need to create it with a reference to the activity's context and then pass + * it to the view with the view's setSurfaceRenderer method. The implementation + * of the 3D world is done by subclassing the Renderer, just like any other * Rajawali application. *

- * Note that it is important to include the KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION configuration - * parameter in order to achieve best results synchronizing the Rajawali virtual world with - * the RGB camera. + * Note that it is important to include the KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION + * configuration parameter in order to achieve best results synchronizing the + * Rajawali virtual world with the RGB camera. */ public class AugmentedRealityActivity extends Activity implements View.OnTouchListener { private static final String TAG = AugmentedRealityActivity.class.getSimpleName(); private TangoRajawaliView mGLView; private AugmentedRealityRenderer mRenderer; - private PointCloudManager mPointCloudManager; + private TangoCameraIntrinsics mCameraIntrinsics; + private TangoPointCloudManager mPointCloudManager; private Tango mTango; private boolean mIsConnected; @@ -80,25 +86,31 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(mGLView); } - // Augmented reality view and renderer - private void startAugmentedreality() { + // Augmented reality view and renderer. + private void startAugmentedReality() { if (!mIsConnected) { try { mIsConnected = true; // Connect to color camera. - mGLView.connectToTangoCamera(mTango, TangoCameraIntrinsics.TANGO_CAMERA_COLOR); + mGLView.connectToTangoCamera(mTango, + TangoCameraIntrinsics.TANGO_CAMERA_COLOR); - // Use default configuration for Tango Service, plus low latency IMU integration. - TangoConfig config = mTango.getConfig(TangoConfig.CONFIG_TYPE_DEFAULT); - // NOTE: Low latency integration is necessary to achieve a precise alignment of - // virtual objects with the RBG image and produce a good AR effect. - config.putBoolean(TangoConfig.KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION, true); + // Use default configuration for Tango Service, plus low latency + // IMU integration. + TangoConfig config = mTango.getConfig( + TangoConfig.CONFIG_TYPE_DEFAULT); + // NOTE: Low latency integration is necessary to achieve a + // precise alignment of virtual objects with the RBG image and + // produce a good AR effect. + config.putBoolean( + TangoConfig.KEY_BOOLEAN_LOWLATENCYIMUINTEGRATION, true); config.putBoolean(TangoConfig.KEY_BOOLEAN_DEPTH, true); mTango.connect(config); - // No need to add any coordinate frame pairs since we are not using - // pose data. So just initialize. - ArrayList framePairs = new ArrayList(); + // No need to add any coordinate frame pairs since we are not + // using pose data. So just initialize. + ArrayList framePairs = + new ArrayList(); mTango.connectListener(framePairs, new OnTangoUpdateListener() { @Override public void onPoseAvailable(TangoPoseData pose) { @@ -107,8 +119,8 @@ public void onPoseAvailable(TangoPoseData pose) { @Override public void onFrameAvailable(int cameraId) { - // Check if the frame available is for the camera we want and - // update its frame on the view. + // Check if the frame available is for the camera we + // want and update its frame on the view. if (cameraId == TangoCameraIntrinsics.TANGO_CAMERA_COLOR) { mGLView.onFrameAvailable(); } @@ -117,7 +129,7 @@ public void onFrameAvailable(int cameraId) { @Override public void onXyzIjAvailable(TangoXyzIjData xyzIj) { // Save the cloud and point data for later use. - mPointCloudManager.updateXyzIjData(xyzIj); + mPointCloudManager.updateXyzIj(xyzIj); } @Override @@ -126,23 +138,24 @@ public void onTangoEvent(TangoEvent event) { } }); - // Get extrinsics from device for use in transforms. This needs to be done after - // connecting Tango and listeners. + // Get extrinsics from device for use in transforms. This needs + // to be done after connecting Tango and listeners. setupExtrinsics(); - // Setup point cloud plane fitting library helper class. - mPointCloudManager = new PointCloudManager(mTango.getCameraIntrinsics( - TangoCameraIntrinsics.TANGO_CAMERA_COLOR)); + mCameraIntrinsics = mTango.getCameraIntrinsics( + TangoCameraIntrinsics.TANGO_CAMERA_COLOR); + mPointCloudManager = new TangoPointCloudManager(); } catch (TangoOutOfDateException e) { - Toast.makeText(getApplicationContext(), R.string.TangoOutOfDateException, - Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext(), + R.string.TangoOutOfDateException, + Toast.LENGTH_SHORT).show(); } } } /** - * Calculates and stores the fixed transformations between the device and the various sensors - * to be used later for transformations between frames. + * Calculates and stores the fixed transformations between the device and + * the various sensors to be used later for transformations between frames. */ private void setupExtrinsics() { // Create camera to IMU transform. @@ -177,7 +190,7 @@ protected void onPause() { protected void onResume() { super.onResume(); if (!mIsConnected) { - startAugmentedreality(); + startAugmentedReality(); } } @@ -191,12 +204,14 @@ public boolean onTouch(View view, MotionEvent motionEvent) { try { doFitPlane(u, v); } catch (TangoException t) { - Toast.makeText(getApplicationContext(), R.string.failed_measurement, - Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext(), + R.string.failed_measurement, + Toast.LENGTH_SHORT).show(); Log.e(TAG, getString(R.string.failed_measurement), t); } catch (SecurityException t) { - Toast.makeText(getApplicationContext(), R.string.failed_permissions, - Toast.LENGTH_SHORT).show(); + Toast.makeText(getApplicationContext(), + R.string.failed_permissions, + Toast.LENGTH_SHORT).show(); Log.e(TAG, getString(R.string.failed_permissions), t); } } @@ -204,29 +219,40 @@ public boolean onTouch(View view, MotionEvent motionEvent) { } /** - * Use the TangoSupport library with point cloud data to calculate the plane of - * the world feature pointed at the location the camera is looking at and update the - * renderer to show a 3D object in that location. + * Use the TangoSupport library with point cloud data to calculate the plane + * of the world feature pointed at the location the camera is looking at and + * update the renderer to show a 3D object in that location. */ private void doFitPlane(float u, float v) { - // NOTE: We request measurement at the latest available time. If we wanted to be even more - // precise, we should use the timestamp of the RGB image rendered at the time the user - // clicked the screen + // NOTE: We request measurement at the latest available time. If we + // wanted to be even more precise, we should use the timestamp of the + // RGB image rendered at the time the user clicked the screen. double measurementTimestamp = 0.0; + TangoXyzIjData xyzIj = mPointCloudManager.getLatestXyzIj(); + + // We need to calculate the transform between the color camera at the + // time the user clicked and the depth camera at the time the depth + // cloud was acquired. + TangoPoseData colorTdepthPose = TangoSupport.calculateRelativePose( + measurementTimestamp, + TangoPoseData.COORDINATE_FRAME_CAMERA_COLOR, xyzIj.timestamp, + TangoPoseData.COORDINATE_FRAME_CAMERA_DEPTH); // Perform plane fitting with the latest available point cloud data. - PointCloudManager.FitPlaneResult planeModelAndTimestamp = - mPointCloudManager.fitPlane(u, v, measurementTimestamp); + IntersectionPointPlaneModelPair intersectionPointPlaneModelPair = + TangoSupport.fitPlaneModelNearClick(xyzIj, mCameraIntrinsics, + colorTdepthPose, u, v); // Get the device pose at the time the plane data was acquired. TangoCoordinateFramePair framePair = new TangoCoordinateFramePair( TangoPoseData.COORDINATE_FRAME_START_OF_SERVICE, TangoPoseData.COORDINATE_FRAME_DEVICE); TangoPoseData devicePose = - mTango.getPoseAtTime(planeModelAndTimestamp.cloudTimestamp, framePair); + mTango.getPoseAtTime(xyzIj.timestamp, framePair); - // Update the AR object location - mRenderer.updateObjectPose(planeModelAndTimestamp.planeModelPair.intersectionPoint, - planeModelAndTimestamp.planeModelPair.planeModel, devicePose); + // Update the AR object location. + mRenderer.updateObjectPose( + intersectionPointPlaneModelPair.intersectionPoint, + intersectionPointPlaneModelPair.planeModel, devicePose); } } diff --git a/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityRenderer.java b/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityRenderer.java index 1679b94a..79d6677b 100644 --- a/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityRenderer.java +++ b/AugmentedRealitySample/app/src/main/java/com/projecttango/experiments/augmentedrealitysample/AugmentedRealityRenderer.java @@ -19,8 +19,6 @@ import android.view.MotionEvent; import com.google.atap.tangoservice.TangoPoseData; -import com.projecttango.rajawali.Pose; -import com.projecttango.rajawali.ar.TangoRajawaliRenderer; import org.rajawali3d.Object3D; import org.rajawali3d.lights.DirectionalLight; @@ -31,15 +29,20 @@ import org.rajawali3d.math.vector.Vector3; import org.rajawali3d.primitives.Cube; +import com.projecttango.rajawali.Pose; +import com.projecttango.rajawali.ar.TangoRajawaliRenderer; + /** - * Very simple example augmented reality renderer which displays two objects in a fixed position - * in the world and the uses the Tango position tracking to keep them in place. + * Very simple example augmented reality renderer which displays two objects in + * a fixed position in the world and the uses the Tango position tracking to + * keep them in place. *

- * This follows the same development model than any regular Rajawali application with the following - * peculiarities: - * - It extends TangoRajawaliArRenderer - * - It calls super.initScene() in the initialization - * - It doesn't do anything with the camera, since that is handled automatically by Tango + * This follows the same development model than any regular Rajawali application + * with the following peculiarities: + * - It extends TangoRajawaliArRenderer. + * - It calls super.initScene() in the initialization. + * - It doesn't do anything with the camera, since that is handled automatically + * by Tango. */ public class AugmentedRealityRenderer extends TangoRajawaliRenderer { private static final float CUBE_SIDE_LENGTH = 0.5f; @@ -55,7 +58,8 @@ public AugmentedRealityRenderer(Context context) { @Override protected void initScene() { - // Remember to call super.initScene() to allow TangoRajawaliArRenderer to be set-up. + // Remember to call super.initScene() to allow TangoRajawaliArRenderer + // to be set-up. super.initScene(); // Add a directional light in an arbitrary direction. @@ -65,7 +69,8 @@ protected void initScene() { light.setPosition(3, 2, 4); getCurrentScene().addLight(light); - // Set-up a material: green with application of the light and instructions. + // Set-up a material: green with application of the light and + // instructions. Material material = new Material(); material.setColor(0xff009900); try { @@ -96,25 +101,29 @@ protected void onRender(long elapsedRealTime, double deltaTime) { // Place the 3D object in the location of the detected plane. mObject.setPosition(mPlanePose.getPosition()); mObject.setOrientation(mPlanePose.getOrientation()); - // Move it forward by half of the size of the cube to make it flush with the plane - // surface. + // Move it forward by half of the size of the cube to make it + // flush with the plane surface. mObject.moveForward(CUBE_SIDE_LENGTH / 2.0f); } } } /** - * Update the 3D object based on the provided measurement point, normal (in depth frame) and - * device pose at the time the point and normal were acquired. + * Update the 3D object based on the provided measurement point, normal (in + * depth frame) and device pose at the time the point and normal were + * acquired. */ public synchronized void updateObjectPose(double[] point, double[] normal, TangoPoseData devicePose) { - mPlanePose = mScenePoseCalcuator.planeFitToOpenGLPose(point, normal, devicePose); + mPlanePose = mScenePoseCalcuator.planeFitToOpenGLPose(point, normal, + devicePose); mPlanePoseUpdated = true; } @Override - public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep, float yOffsetStep, int xPixelOffset, int yPixelOffset) { + public void onOffsetsChanged(float xOffset, float yOffset, + float xOffsetStep, float yOffsetStep, + int xPixelOffset, int yPixelOffset) { } diff --git a/AugmentedRealitySample/app/src/main/res/menu/main.xml b/AugmentedRealitySample/app/src/main/res/menu/main.xml deleted file mode 100644 index 76c1d564..00000000 --- a/AugmentedRealitySample/app/src/main/res/menu/main.xml +++ /dev/null @@ -1,11 +0,0 @@ -

- - - - diff --git a/AugmentedRealitySample/app/src/main/res/values/strings.xml b/AugmentedRealitySample/app/src/main/res/values/strings.xml index 1679b024..8cf24e22 100644 --- a/AugmentedRealitySample/app/src/main/res/values/strings.xml +++ b/AugmentedRealitySample/app/src/main/res/values/strings.xml @@ -2,8 +2,8 @@ AugmentedRealitySample - Settings "Tango service outdated!" Failed to fit plane Permissions required! + diff --git a/AugmentedRealitySample/gradle/wrapper/gradle-wrapper.jar b/AugmentedRealitySample/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a..c97a8bdb 100644 Binary files a/AugmentedRealitySample/gradle/wrapper/gradle-wrapper.jar and b/AugmentedRealitySample/gradle/wrapper/gradle-wrapper.jar differ diff --git a/MotionTrackingJava/app/src/main/java/com/projecttango/experiments/javamotiontracking/MotionTrackingActivity.java b/MotionTrackingJava/app/src/main/java/com/projecttango/experiments/javamotiontracking/MotionTrackingActivity.java index 589c1d79..e29035a5 100644 --- a/MotionTrackingJava/app/src/main/java/com/projecttango/experiments/javamotiontracking/MotionTrackingActivity.java +++ b/MotionTrackingJava/app/src/main/java/com/projecttango/experiments/javamotiontracking/MotionTrackingActivity.java @@ -25,7 +25,6 @@ import com.google.atap.tangoservice.TangoOutOfDateException; import com.google.atap.tangoservice.TangoPoseData; import com.google.atap.tangoservice.TangoXyzIjData; -import com.projecttango.tangoutils.TangoPoseUtilities; import android.app.Activity; import android.content.Intent; @@ -39,6 +38,8 @@ import android.widget.TextView; import android.widget.Toast; +import com.projecttango.tangoutils.TangoPoseUtilities; + import org.rajawali3d.surface.IRajawaliSurface; import org.rajawali3d.surface.RajawaliSurfaceView; @@ -54,7 +55,9 @@ public class MotionTrackingActivity extends Activity implements View.OnClickList private static final String TAG = MotionTrackingActivity.class.getSimpleName(); private static final int SECS_TO_MILLISECS = 1000; - private static final int UPDATE_INTERVAL_MS = 100; + private static final double UPDATE_INTERVAL_MS = 100.0f; + private static final DecimalFormat FORMAT_THREE_DECIMAL = new DecimalFormat("0.000"); + private Tango mTango; private TangoConfig mConfig; private TextView mDeltaTextView; @@ -66,14 +69,16 @@ public class MotionTrackingActivity extends Activity implements View.OnClickList private TextView mApplicationVersionTextView; private TextView mTangoEventTextView; private Button mMotionResetButton; - private float mPreviousTimeStamp; - private int mPreviousPoseStatus; - private int mCount; - private float mDeltaTime; private boolean mIsAutoRecovery; private MotionTrackingRajawaliRenderer mRenderer; - private TangoPoseData mPose; - public static Object mUiThreadLock = new Object(); + + // State tracking variables for pose callback handler. If these are + // referenced from the main thread, they need to be synchronized with the + // pose handler callback. + private double mPreviousTimeStamp = 0.0; + private int mPreviousPoseStatus = TangoPoseData.POSE_INVALID; + private int mCount = 0; + private double mTimeToNextUpdate = UPDATE_INTERVAL_MS; @Override protected void onCreate(Bundle savedInstanceState) { @@ -87,9 +92,8 @@ protected void onCreate(Bundle savedInstanceState) { mConfig = setupTangoConfig(mTango, mIsAutoRecovery); setupTextViewsAndButtons(mConfig); mRenderer = setupGLViewAndRenderer(); - startUIThread(); } - + /** * Sets Rajawalisurface view and its renderer. This is ideally called only once in onCreate. */ @@ -179,32 +183,63 @@ private void setTangoListeners() { // Listen for new Tango data mTango.connectListener(framePairs, new OnTangoUpdateListener() { - @Override public void onPoseAvailable(final TangoPoseData pose) { - // Update the OpenGL renderable objects with the new Tango Pose data. - // Note that locking for thread safe access with the OpenGL loop is done entirely - // in the renderer. + // Update the OpenGL renderable objects with the new Tango Pose + // data. Note that locking for thread safe access with the + // OpenGL loop is done entirely in the renderer. mRenderer.updateDevicePose(pose); - - // Make sure to have atomic access to Tango Pose Data so that the UI - // the UI loop doesn't interfere while Pose call back is updating the data - synchronized (mUiThreadLock) { - mPose = pose; - - //Now lets log some interesting statistics of Motion Tracking like - // Delta Time between two Poses, number of poses since the initialization state. - mDeltaTime = (float) (pose.timestamp - mPreviousTimeStamp) * SECS_TO_MILLISECS; - mPreviousTimeStamp = (float) pose.timestamp; - // Log whenever Motion Tracking enters an invalid state - if (!mIsAutoRecovery && (pose.statusCode == TangoPoseData.POSE_INVALID)) { - Log.w(TAG, "Invalid State"); - } - if (mPreviousPoseStatus != pose.statusCode) { - mCount = 0; - } - mCount++; - mPreviousPoseStatus = pose.statusCode; + + // Now lets log some interesting statistics of Motion Tracking + // like Delta Time between two Poses, number of poses since the + // initialization state. + final double deltaTime = (pose.timestamp - mPreviousTimeStamp) + * SECS_TO_MILLISECS; + + mPreviousTimeStamp = pose.timestamp; + // Log whenever Motion Tracking enters an invalid state + if (!mIsAutoRecovery && (pose.statusCode == TangoPoseData.POSE_INVALID)) { + Log.w(TAG, "Invalid State"); + } + if (mPreviousPoseStatus != pose.statusCode) { + mCount = 0; + } + mCount++; + final int count = mCount; + mPreviousPoseStatus = pose.statusCode; + + // Throttle updates to the UI based on UPDATE_INTERVAL_MS. + mTimeToNextUpdate -= deltaTime; + boolean updateUI = false; + if(mTimeToNextUpdate < 0.0) { + mTimeToNextUpdate = UPDATE_INTERVAL_MS; + updateUI = true; + } + + // If the pose is not valid, we may not get another callback so make sure to update + // the UI during this call + if (pose.statusCode != TangoPoseData.POSE_VALID) { + updateUI = true; + } + + if(updateUI) { + final String translationString = + TangoPoseUtilities.getTranslationString(pose, FORMAT_THREE_DECIMAL); + final String quaternionString = + TangoPoseUtilities.getQuaternionString(pose, FORMAT_THREE_DECIMAL); + final String status = TangoPoseUtilities.getStatusString(pose); + + runOnUiThread(new Runnable() { + @Override + public void run() { + // Display pose data on screen in TextViews. + mPoseTextView.setText(translationString); + mQuatTextView.setText(quaternionString); + mPoseCountTextView.setText(Integer.toString(count)); + mDeltaTextView.setText(FORMAT_THREE_DECIMAL.format(deltaTime)); + mPoseStatusTextView.setText(status); + } + }); } } @@ -301,51 +336,4 @@ public boolean onTouchEvent(MotionEvent event) { mRenderer.onTouchEvent(event); return true; } - - /** - * Create a separate thread to update Log information on UI at the specified - * interval of UPDATE_INTERVAL_MS. This function also makes sure to have access - * to the mPose atomically. - */ - private void startUIThread() { - new Thread(new Runnable() { - DecimalFormat threeDec = new DecimalFormat("00.000"); - @Override - public void run() { - while (true) { - try { - Thread.sleep(UPDATE_INTERVAL_MS); - runOnUiThread(new Runnable() { - @Override - public void run() { - try { - synchronized (mUiThreadLock) { - if (mPose == null) { - return; - } - String translationString = - TangoPoseUtilities.getTranslationString(mPose, threeDec); - String quaternionString = - TangoPoseUtilities.getQuaternionString(mPose, threeDec); - String status = TangoPoseUtilities.getStatusString(mPose); - // Display pose data on screen in TextViews - mPoseTextView.setText(translationString); - mQuatTextView.setText(quaternionString); - mPoseCountTextView.setText(Integer.toString(mCount)); - mDeltaTextView.setText(threeDec.format(mDeltaTime)); - mPoseStatusTextView.setText(status); - } - } catch (NullPointerException e) { - e.printStackTrace(); - } - } - }); - - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - }).start(); - } -} \ No newline at end of file +} diff --git a/MotionTrackingJava/gradle/wrapper/gradle-wrapper.jar b/MotionTrackingJava/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a..c97a8bdb 100644 Binary files a/MotionTrackingJava/gradle/wrapper/gradle-wrapper.jar and b/MotionTrackingJava/gradle/wrapper/gradle-wrapper.jar differ diff --git a/PointCloudJava/app/src/main/java/com/projecttango/experiments/javapointcloud/PointCloudActivity.java b/PointCloudJava/app/src/main/java/com/projecttango/experiments/javapointcloud/PointCloudActivity.java index 18065b42..16aa85ee 100644 --- a/PointCloudJava/app/src/main/java/com/projecttango/experiments/javapointcloud/PointCloudActivity.java +++ b/PointCloudJava/app/src/main/java/com/projecttango/experiments/javapointcloud/PointCloudActivity.java @@ -15,6 +15,10 @@ */ package com.projecttango.experiments.javapointcloud; + +import com.google.atap.tango.ux.TangoUx; +import com.google.atap.tango.ux.TangoUx.StartParams; +import com.google.atap.tango.ux.TangoUxLayout; import com.google.atap.tango.ux.UxExceptionEvent; import com.google.atap.tango.ux.UxExceptionEventListener; import com.google.atap.tangoservice.Tango; @@ -28,12 +32,6 @@ import com.google.atap.tangoservice.TangoPoseData; import com.google.atap.tangoservice.TangoXyzIjData; -import com.google.atap.tango.ux.TangoUx; -import com.google.atap.tango.ux.TangoUx.StartParams; -import com.google.atap.tango.ux.TangoUxLayout; -import com.projecttango.tangoutils.TangoPoseUtilities; - - import android.app.Activity; import android.content.Intent; import android.content.pm.PackageInfo; @@ -47,6 +45,8 @@ import android.widget.TextView; import android.widget.Toast; +import com.projecttango.tangoutils.TangoPoseUtilities; + import org.rajawali3d.surface.RajawaliSurfaceView; import java.lang.Override; @@ -85,22 +85,19 @@ public class PointCloudActivity extends Activity implements OnClickListener { private Button mTopDownButton; private int mCount; - private int mPreviousPoseStatus; - private int mPointCount; - private float mDeltaTime; - private float mPosePreviousTimeStamp; - private float mXyIjPreviousTimeStamp; - private float mCurrentTimeStamp; - private float mPointCloudFrameDelta; - private float mAverageDepth; + private int mPreviousPoseStatus = TangoPoseData.POSE_INVALID; + private double mPosePreviousTimeStamp; + private double mXyIjPreviousTimeStamp; private boolean mIsTangoServiceConnected; private TangoPoseData mPose; private PointCloudManager mPointCloudManager; private TangoUx mTangoUx; - private static final int UPDATE_INTERVAL_MS = 100; - private Object mUiPoseLock = new Object(); - private Object mUiDepthLock = new Object(); + private static final DecimalFormat FORMAT_THREE_DECIMAL = new DecimalFormat("0.000"); + private static final double UPDATE_INTERVAL_MS = 100.0; + + private double mPoseTimeToNextUpdate = UPDATE_INTERVAL_MS; + private double mXyzIjTimeToNextUpdate = UPDATE_INTERVAL_MS; @Override protected void onCreate(Bundle savedInstanceState) { @@ -117,7 +114,6 @@ protected void onCreate(Bundle savedInstanceState) { mRenderer = setupGLViewAndRenderer(mPointCloudManager); mTangoUx = setupTangoUxAndLayout(); mIsTangoServiceConnected = false; - startUIThread(); } @Override @@ -203,21 +199,41 @@ public void onPoseAvailable(final TangoPoseData pose) { if (mTangoUx != null) { mTangoUx.updatePoseStatus(pose.statusCode); } - // Make sure to have atomic access to Tango Pose Data so that - // render loop doesn't interfere while Pose call back is updating - // the data. - synchronized (mUiPoseLock) { - mPose = pose; - // Calculate the delta time from previous pose. - mDeltaTime = (float) (pose.timestamp - mPosePreviousTimeStamp) - * SECS_TO_MILLISECS; - mPosePreviousTimeStamp = (float) pose.timestamp; - if (mPreviousPoseStatus != pose.statusCode) { - mCount = 0; - } - mCount++; - mPreviousPoseStatus = pose.statusCode; + + mPose = pose; + // Calculate the delta time from previous pose. + final double deltaTime = (pose.timestamp - mPosePreviousTimeStamp) + * SECS_TO_MILLISECS; + mPosePreviousTimeStamp = pose.timestamp; + if (mPreviousPoseStatus != pose.statusCode) { + mCount = 0; + } + mCount++; + mPreviousPoseStatus = pose.statusCode; + mPoseTimeToNextUpdate -= deltaTime; + + if (mPoseTimeToNextUpdate < 0.0) { + mPoseTimeToNextUpdate = UPDATE_INTERVAL_MS; + + final String translationString + = TangoPoseUtilities.getTranslationString(mPose, FORMAT_THREE_DECIMAL); + final String quaternionString + = TangoPoseUtilities.getQuaternionString(mPose, FORMAT_THREE_DECIMAL); + final String status = TangoPoseUtilities.getStatusString(mPose); + final String countString = Integer.toString(mCount); + + runOnUiThread(new Runnable() { + @Override + public void run() { + mPoseTextView.setText(translationString); + mQuatTextView.setText(quaternionString); + mPoseCountTextView.setText(countString); + mDeltaTextView.setText(FORMAT_THREE_DECIMAL.format(deltaTime)); + mPoseStatusTextView.setText(status); + } + }); } + mRenderer.updateDevicePose(pose); } @@ -227,28 +243,30 @@ public void onXyzIjAvailable(final TangoXyzIjData xyzIj) { mTangoUx.updateXyzCount(xyzIj.xyzCount); } mPointCloudManager.updateCallbackBufferAndSwap(xyzIj.xyz, xyzIj.xyzCount); - TangoPoseData pointCloudPose = mTango.getPoseAtTime(mCurrentTimeStamp, + TangoPoseData pointCloudPose = mTango.getPoseAtTime(xyzIj.timestamp, framePairs.get(0)); mRenderer.updatePointCloudPose(pointCloudPose); - // Make sure to have atomic access to TangoXyzIjData so that - // UI loop doesn't interfere while onXYZijAvailable callback is updating - // the mPoint cloud data. - synchronized (mUiDepthLock) { - mCurrentTimeStamp = (float) xyzIj.timestamp; - mPointCloudFrameDelta = (mCurrentTimeStamp - mXyIjPreviousTimeStamp) - * SECS_TO_MILLISECS; - mXyIjPreviousTimeStamp = mCurrentTimeStamp; - mAverageDepth = getAveragedDepth(xyzIj.xyz); - try { - mPointCount = xyzIj.xyzCount; - } catch (TangoErrorException e) { - Toast.makeText(getApplicationContext(), R.string.TangoError, - Toast.LENGTH_SHORT).show(); - } catch (TangoInvalidException e) { - Toast.makeText(getApplicationContext(), R.string.TangoError, - Toast.LENGTH_SHORT).show(); - } + final double currentTimeStamp = xyzIj.timestamp; + final double pointCloudFrameDelta = (currentTimeStamp - mXyIjPreviousTimeStamp) + * SECS_TO_MILLISECS; + mXyIjPreviousTimeStamp = currentTimeStamp; + final double averageDepth = getAveragedDepth(xyzIj.xyz); + + mXyzIjTimeToNextUpdate -= pointCloudFrameDelta; + + if (mXyzIjTimeToNextUpdate < 0.0) { + mXyzIjTimeToNextUpdate = UPDATE_INTERVAL_MS; + final String pointCountString = Integer.toString(xyzIj.xyzCount); + + runOnUiThread(new Runnable() { + @Override + public void run() { + mPointCountTextView.setText(pointCountString); + mFrequencyTextView.setText(FORMAT_THREE_DECIMAL.format(pointCloudFrameDelta)); + mAverageZTextView.setText(FORMAT_THREE_DECIMAL.format(averageDepth)); + } + }); } } @@ -272,53 +290,6 @@ public void onFrameAvailable(int cameraId) { }); } - /** - * Create a separate thread to update Log information on UI at the specified interval of - * UPDATE_INTERVAL_MS. This function also makes sure to have access to the mPose atomically. - */ - private void startUIThread() { - new Thread(new Runnable() { - final DecimalFormat threeDec = new DecimalFormat("0.000"); - - @Override - public void run() { - while (true) { - try { - Thread.sleep(UPDATE_INTERVAL_MS); - // Update the UI with TangoPose information - runOnUiThread(new Runnable() { - @Override - public void run() { - synchronized (mUiPoseLock) { - if (mPose == null) { - return; - } - String translationString = TangoPoseUtilities.getTranslationString(mPose, threeDec); - String quaternionString = TangoPoseUtilities.getQuaternionString(mPose, threeDec); - String status = TangoPoseUtilities.getStatusString(mPose); - mPoseTextView.setText(translationString); - mQuatTextView.setText(quaternionString); - mPoseCountTextView.setText(Integer.toString(mCount)); - mDeltaTextView.setText(threeDec.format(mDeltaTime)); - mPoseStatusTextView.setText(status); - } - synchronized (mUiDepthLock) { - // Display number of points in the mPoint cloud - mPointCountTextView.setText(Integer.toString(mPointCount)); - mFrequencyTextView.setText("" - + threeDec.format(mPointCloudFrameDelta)); - mAverageZTextView.setText("" + threeDec.format(mAverageDepth)); - } - } - }); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - }).start(); - } - private void setupExtrinsics() { TangoCoordinateFramePair framePair = new TangoCoordinateFramePair(); framePair.baseFrame = TangoPoseData.COORDINATE_FRAME_IMU; @@ -453,14 +424,14 @@ private TangoUx setupTangoUxAndLayout(){ * @return Average depth. */ private float getAveragedDepth(FloatBuffer pointCloudBuffer){ - mPointCount = pointCloudBuffer.capacity() / 3; + int pointCount = pointCloudBuffer.capacity() / 3; float totalZ = 0; float averageZ = 0; for (int i = 0; i < pointCloudBuffer.capacity() - 3; i = i + 3) { totalZ = totalZ + pointCloudBuffer.get(i + 2); } - if (mPointCount != 0) - averageZ = totalZ / mPointCount; + if (pointCount != 0) + averageZ = totalZ / pointCount; return averageZ; } diff --git a/PointCloudJava/gradle/wrapper/gradle-wrapper.jar b/PointCloudJava/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a..c97a8bdb 100644 Binary files a/PointCloudJava/gradle/wrapper/gradle-wrapper.jar and b/PointCloudJava/gradle/wrapper/gradle-wrapper.jar differ diff --git a/QuickstartJava/app/src/main/java/com/projecttango/experiments/quickstartjava/MainActivity.java b/QuickstartJava/app/src/main/java/com/projecttango/experiments/quickstartjava/MainActivity.java index f1fac3ab..dfd1aa95 100644 --- a/QuickstartJava/app/src/main/java/com/projecttango/experiments/quickstartjava/MainActivity.java +++ b/QuickstartJava/app/src/main/java/com/projecttango/experiments/quickstartjava/MainActivity.java @@ -16,8 +16,6 @@ package com.projecttango.experiments.quickstartjava; -import java.util.ArrayList; - import com.google.atap.tangoservice.Tango; import com.google.atap.tangoservice.Tango.OnTangoUpdateListener; import com.google.atap.tangoservice.TangoConfig; @@ -37,6 +35,7 @@ import android.widget.TextView; import android.widget.Toast; +import java.util.ArrayList; /** * Main Activity for the Tango Java Quickstart. Demonstrates establishing a @@ -49,13 +48,19 @@ public class MainActivity extends Activity { private static final String sTranslationFormat = "Translation: %f, %f, %f"; private static final String sRotationFormat = "Rotation: %f, %f, %f, %f"; + private static final int SECS_TO_MILLISECS = 1000; + private static final double UPDATE_INTERVAL_MS = 100.0; + + private double mPreviousTimeStamp; + private double mTimeToNextUpdate = UPDATE_INTERVAL_MS; + private TextView mTranslationTextView; private TextView mRotationTextView; private Tango mTango; private TangoConfig mConfig; private boolean mIsTangoServiceConnected; - private boolean mIsProcessing = false; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -137,12 +142,6 @@ private void setTangoListeners() { @SuppressLint("DefaultLocale") @Override public void onPoseAvailable(TangoPoseData pose) { - if (mIsProcessing) { - Log.i(TAG, "Processing UI"); - return; - } - mIsProcessing = true; - // Format Translation and Rotation data final String translationMsg = String.format(sTranslationFormat, pose.translation[0], pose.translation[1], @@ -155,19 +154,28 @@ public void onPoseAvailable(TangoPoseData pose) { String logMsg = translationMsg + " | " + rotationMsg; Log.i(TAG, logMsg); - // Display data in TextViews. This must be done inside a - // runOnUiThread call because - // it affects the UI, which will cause an error if performed - // from the Tango - // service thread - runOnUiThread(new Runnable() { - @Override - public void run() { - mTranslationTextView.setText(translationMsg); - mRotationTextView.setText(rotationMsg); - mIsProcessing = false; - } - }); + final double deltaTime = (pose.timestamp - mPreviousTimeStamp) + * SECS_TO_MILLISECS; + mPreviousTimeStamp = pose.timestamp; + mTimeToNextUpdate -= deltaTime; + + // Throttle updates to the UI based on UPDATE_INTERVAL_MS. + if (mTimeToNextUpdate < 0.0) { + mTimeToNextUpdate = UPDATE_INTERVAL_MS; + + // Display data in TextViews. This must be done inside a + // runOnUiThread call because + // it affects the UI, which will cause an error if performed + // from the Tango + // service thread + runOnUiThread(new Runnable() { + @Override + public void run() { + mRotationTextView.setText(rotationMsg); + mTranslationTextView.setText(translationMsg); + } + }); + } } @Override diff --git a/QuickstartJava/gradle/wrapper/gradle-wrapper.jar b/QuickstartJava/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a..c97a8bdb 100644 Binary files a/QuickstartJava/gradle/wrapper/gradle-wrapper.jar and b/QuickstartJava/gradle/wrapper/gradle-wrapper.jar differ diff --git a/TangoReleaseLibs/aar/TangoUtils.aar b/TangoReleaseLibs/aar/TangoUtils.aar index 189cbad2..8c379cdb 100644 Binary files a/TangoReleaseLibs/aar/TangoUtils.aar and b/TangoReleaseLibs/aar/TangoUtils.aar differ diff --git a/TangoReleaseLibs/aar/tango-ux-support-library.aar b/TangoReleaseLibs/aar/tango-ux-support-library.aar index dc181b25..1248aa50 100644 Binary files a/TangoReleaseLibs/aar/tango-ux-support-library.aar and b/TangoReleaseLibs/aar/tango-ux-support-library.aar differ diff --git a/TangoReleaseLibs/aar/tango_support_java_lib.aar b/TangoReleaseLibs/aar/tango_support_java_lib.aar index 4df01320..317b06a1 100644 Binary files a/TangoReleaseLibs/aar/tango_support_java_lib.aar and b/TangoReleaseLibs/aar/tango_support_java_lib.aar differ diff --git a/TangoReleaseLibs/jar/tango_java_lib.jar b/TangoReleaseLibs/jar/tango_java_lib.jar index 63199d65..8f81273f 100644 Binary files a/TangoReleaseLibs/jar/tango_java_lib.jar and b/TangoReleaseLibs/jar/tango_java_lib.jar differ diff --git a/TangoUtils/gradle/wrapper/gradle-wrapper.jar b/TangoUtils/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a..c97a8bdb 100644 Binary files a/TangoUtils/gradle/wrapper/gradle-wrapper.jar and b/TangoUtils/gradle/wrapper/gradle-wrapper.jar differ diff --git a/VideoOverlaySample/app/src/main/AndroidManifest.xml b/VideoOverlaySample/app/src/main/AndroidManifest.xml index 04c2e995..4e03a93d 100644 --- a/VideoOverlaySample/app/src/main/AndroidManifest.xml +++ b/VideoOverlaySample/app/src/main/AndroidManifest.xml @@ -7,7 +7,7 @@ - +