This is a strange one and I hope that someone can at least give me a direction to look in.
My Android application uses GoogleMap API v2. In the app, I run an activity off OnClickInfoWindowListener on one of the markers. In detail, when I click on the particular marker, an InfoWindow of that marker appears. Next when I click on the InfoWindow, it launches another activity.
The problem is that when I return to GoogleMap from that activity, the particular marker which launched the activity, is not responsive. By responsive, I mean when I click on it, I do not get an InfoWindow. There is no such problem with the other markers. To fix the problem, I either move or zoom on the map or click on another marker to show its InfoWindow, then the original marker works normally. I cannot see any red stuff on the LogCat.
I also run the map off a ListView and there is no problem (that I can see).
Any suggestions on what to look at are very welcome!
Edit 1 :
This part is the InfoWindowClickListener setup ...
// Set up info Window Click Listener
googleMap
.setOnInfoWindowClickListener(new OnInfoWindowClickListener() {
#Override
public void onInfoWindowClick(Marker mkr) {
// Default open file
// menu option : edit file information
// menu option : delete
Log.d(TAG, "InfoWindow Click detected.");
final GeoFileData gfd = getFromHashMap(mkr);
if (editGeoFile) {
editGeoFile = false;
editFileInfo(gfd);
} else if (deleteGeoFile) {
deleteGeoFile = false;
deleteFile(gfd, mkr);
} else {
openFile(gfd);
}
}
});
The openFile routine which launches the Activity
// Public and Routines used by the main loop
private void openFile (GeoFileData gfd) {
int typeIndex = gfd.getTypeIndex();
switch(typeIndex) {
case 0 :
case 1 :
case 2 :
case 3 :
// Spen file by default
Intent notePadIntent = new Intent(getBaseContext(), NotePad.class);
Bundle b = new Bundle();
b.putParcelable(MAIN_NOTEPAD_GFD, gfd);
notePadIntent.putExtras(b);
startActivityForResult(notePadIntent, SPEN_NOTEPAD_CODE);
break;
default :
Log.w(TAG, "Unknown file.");
Toast.makeText(this, getString(R.string.toast_unknown_file), Toast.LENGTH_LONG).show();
break;
}
}
The starting part of the launched activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_spen_notepad);
Bundle extras = getIntent().getExtras();
if (extras != null) {
inputGfd = extras.getParcelable(PreznsActivity.MAIN_NOTEPAD_GFD);
}
extras.clear();
mContext = this;
// Spen
boolean isSpenFeatureEnabled = false;
Spen spenPackage = new Spen();
try {
spenPackage.initialize(this);
isSpenFeatureEnabled = spenPackage.isFeatureEnabled(Spen.DEVICE_PEN);
} catch (SsdkUnsupportedException e) {
if( SDKUtils.processUnsupportedException(this, e) == true) {
return;
}
} catch (Exception e1) {
Toast.makeText(mContext, "Cannot initialize Spen.",
Toast.LENGTH_SHORT).show();
e1.printStackTrace();
finish();
}
FrameLayout spenViewContainer =
(FrameLayout) findViewById(R.id.spenViewContainer);
RelativeLayout spenViewLayout =
(RelativeLayout) findViewById(R.id.spenViewLayout);
// PenSettingView
mPenSettingView =
new SpenSettingPenLayout(mContext, new String(),
spenViewLayout);
if (mPenSettingView == null) {
Toast.makeText(mContext, "Cannot create new PenSettingView.",
Toast.LENGTH_SHORT).show();
finish();
}
// EraserSettingView
mEraserSettingView =
new SpenSettingEraserLayout(mContext, new String(),
spenViewLayout);
if (mEraserSettingView == null) {
Toast.makeText(mContext, "Cannot create new EraserSettingView.",
Toast.LENGTH_SHORT).show();
finish();
}
// TextSettingView
mTextSettingView = new SpenSettingTextLayout(mContext, new String(), new HashMap<String, String>(), spenViewLayout);
if (mTextSettingView == null) {
Toast.makeText(mContext, "Cannot craeate new TextSettingView.", Toast.LENGTH_SHORT).show();
finish();
}
spenViewContainer.addView(mPenSettingView);
spenViewContainer.addView(mEraserSettingView);
spenViewContainer.addView(mTextSettingView);
// SpenSurfaceView
mSpenSurfaceView = new SpenSurfaceView(mContext);
if (mSpenSurfaceView == null) {
Toast.makeText(mContext, "Cannot create new SpenSurfaceView.",
Toast.LENGTH_SHORT).show();
finish();
}
spenViewLayout.addView(mSpenSurfaceView);
mPenSettingView.setCanvasView(mSpenSurfaceView);
mEraserSettingView.setCanvasView(mSpenSurfaceView);
mTextSettingView.setCanvasView(mSpenSurfaceView);
//
Display display = getWindowManager().getDefaultDisplay();
mScreenRect = new Rect();
display.getRectSize(mScreenRect);
// SpenNoteDoc
try {
mSpenNoteDoc =
new SpenNoteDoc(mContext, mScreenRect.width(), mScreenRect.height());
} catch (IOException e) {
Toast.makeText(mContext, "Cannot create new NoteDoc",
Toast.LENGTH_SHORT).show();
e.printStackTrace();
finish();
} catch (Exception e) {
e.printStackTrace();
finish();
}
// NoteDoc
mSpenPageDoc = mSpenNoteDoc.appendPage();
mSpenPageDoc.setBackgroundColor(0xFFD6E6F5);
mSpenPageDoc.clearHistory();
// PageDoc
mSpenSurfaceView.setPageDoc(mSpenPageDoc, true);
initSettingInfo();
// Listener
mSpenSurfaceView.setTouchListener(mPenTouchListener);
mSpenSurfaceView.setColorPickerListener(mColorPickerListener);
mSpenSurfaceView.setTextChangeListener(mTextChangeListener);
mSpenSurfaceView.setReplayListener(mReplayListener);
mSpenPageDoc.setHistoryListener(mHistoryListener);
mEraserSettingView.setEraserListener(mEraserListener);
mSpenSurfaceView.setFlickListener(mFlickListener);
// Button
mTextObjBtn = (ImageView) findViewById(R.id.textObjBtn);
mTextObjBtn.setOnClickListener(mTextObjBtnClickListener);
mPenBtn = (ImageView) findViewById(R.id.penBtn);
mPenBtn.setOnClickListener(mPenBtnClickListener);
mEraserBtn = (ImageView) findViewById(R.id.eraserBtn);
mEraserBtn.setOnClickListener(mEraserBtnClickListener);
mUndoBtn = (ImageView) findViewById(R.id.undoBtn);
mUndoBtn.setOnClickListener(undoNredoBtnClickListener);
mUndoBtn.setEnabled(mSpenPageDoc.isUndoable());
mRedoBtn = (ImageView) findViewById(R.id.redoBtn);
mRedoBtn.setOnClickListener(undoNredoBtnClickListener);
mRedoBtn.setEnabled(mSpenPageDoc.isRedoable());
mImgObjBtn = (ImageView) findViewById(R.id.imgObjBtn);
mImgObjBtn.setOnClickListener(mImgObjBtnClickListener);
mAddPageBtn = (ImageView) findViewById(R.id.addPageBtn);
mAddPageBtn.setOnClickListener(mAddPageBtnClickListener);
mTxtView = (TextView) findViewById(R.id.spen_page);
mTxtView.setText("Page" + mSpenNoteDoc.getPageIndexById(mSpenPageDoc.getId()));
selectButton(mPenBtn);
String filePath = inputGfd.getFileDirectory();
mFilePath = new File(filePath);
if (!mFilePath.exists()) {
if (!mFilePath.mkdirs()) {
Toast.makeText(mContext, "Save Path Creation Error", Toast.LENGTH_SHORT).show();
return;
}
}
mSpenPageDoc.startRecord();
File loadFile = new File(inputGfd.getFileDirectory(), inputGfd.getFileName());
if (loadFile.exists()) {
loadNoteFile();
} else {
Log.w(TAG, "File does not exist!");
}
if(isSpenFeatureEnabled == false) {
mToolType = SpenSurfaceView.TOOL_FINGER;
mSpenSurfaceView.setToolTypeAction(mToolType,
SpenSurfaceView.ACTION_STROKE);
Toast.makeText(mContext,
"Device does not support Spen. \n You can draw stroke by finger",
Toast.LENGTH_SHORT).show();
}
}
One of the returns for the activity
private boolean saveNoteFile(final boolean isClose) {
// file save
// note file
String saveFilePath = inputGfd.getFileDirectory() + File.separator;
String fileName = inputGfd.getFileName();
if (!fileName.equals("")) {
saveFilePath += fileName;
saveNoteFile(saveFilePath);
if (isClose)
finish();
} else {
Toast
.makeText(mContext, "Invalid filename !!!", Toast.LENGTH_LONG)
.show();
}
return true;
}
and finally the destroy routine,
#Override
protected void onDestroy() {
Log.d(TAG, "NotePad onDestroy()");
super.onDestroy();
if (mSpenNoteDoc != null && mSpenPageDoc.isRecording()) {
mSpenPageDoc.stopRecord();
}
if (mPenSettingView != null) {
mPenSettingView.close();
}
if (mEraserSettingView != null) {
mEraserSettingView.close();
}
if (mTextSettingView != null) {
mTextSettingView.close();
}
if(mSpenSurfaceView != null) {
if (mSpenSurfaceView.getReplayState() == SpenSurfaceView.REPLAY_STATE_PLAYING) {
mSpenSurfaceView.stopReplay();
}
mSpenSurfaceView.closeControl();
mSpenSurfaceView.close();
mSpenSurfaceView = null;
}
if(mSpenNoteDoc != null) {
try {
if (isDiscard)
mSpenNoteDoc.discard();
else
mSpenNoteDoc.close();
} catch (Exception e) {
e.printStackTrace();
}
mSpenNoteDoc = null;
}
};
Thanks!
This is likely a bug in Google Maps Android API v2 itself.
I encounter it in my app. When you open "Declusterification" demo, click on yellow marker with 10 in the center and a new marker (red default) appears in the same spot, this new marker cannot be interacted with to show info window without moving the map.
If you happen to figure out SSCCE for it, I suggest posting it on gmaps-api-issues. I'll support it. If I do find simple example to show this issue, I'll also post an update here.
To close up this question.
GoogleMap markers exhibit the anomalies mentioned in this thread and currently the issue has been fed back to Google. There are two apparent "workarounds" to the problem but how effective they are is not clear:
1st workaround : work within the limitations of .clear(). An activated marker cannot be deactivated with .clear().
2nd workaround : after returning from the activity, perform a camera update. This apparently resets the activation of the marker.
Related
my app is fairly simple and always works IF my IOT device is up.
i need to load a popup and show the ReScan button on the toolbar if the device cannot be found.
the app preloads IPaddress="-" and loads 2 asyncTask(s)
one uses NsdManager.DiscoveryListener to find the mDNS name and loads the IP into IPaddress
this task watches to see IPaddress change and gets the presets from the device by JSON and sets up the UI or pops up the error dialog with instructions if not found.
MY PROBLEM:
when counter >= 15 , i show the "Rescan" Button on the toolbar with setMenuVisible() then popup the error dialog but when the button in the dialog is pressed to close the dialog, the "Rescan" Button disappears again.
Also times out in about 5 seconds.
how do i get the "Rescan" Button to stay?
.
private class getSettingsFromClock extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
String mlooper = IPaddress;
Log.i(TAG, "LOG getSettingsFromClock doInBackground started ");
int counter = 0;
while ( mlooper.equals("-") ) {
mlooper = IPaddress;
try {
Thread.sleep(600);
} catch (InterruptedException e) {
e.printStackTrace();
}
counter++;
if (counter >= 15) // in normal operation counter never goes above 3
{
Log.i(TAG, "LOG getSettingsFromClock - NO IP Found, count= " + counter );
runOnUiThread(new Runnable() {
#Override
public void run() {
setMenuVisible( true, R.id.action_rescan); // show rescan button on toolbar
try { // delay is debugging only
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//scanning failed Popup Dialog
final Dialog dialog = new Dialog(context );
dialog.setContentView(R.layout.popup);
dialog.setTitle("Scan Error");
Button button = dialog.findViewById(R.id.Button01);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View view) {
dialog.dismiss();
}
});
dialog.show();
Toast.makeText(getApplicationContext(),
"Could Not get presets from clock. \n check Clock is on and on WiFi\n and reload app.",
Toast.LENGTH_LONG).show();
}
});
break;
}
}
if( IPaddress != "-" )
{
// gets JSON here
} else
{
// add popup - IOT Not found
}
// JSON starts here
if (JSON_return != null) {
try {
// loads presets from JSON to UI here
} catch (final JSONException e) {
Log.e(TAG, "LOG, JSON parsing error: " + e.getMessage());
}
} else
{
Log.e(TAG, "LOG, Could Not get JSON from Clock.");
}
return null;
}
} // end asyncTask class
// remember to run on main thread
// NOTE; private Menu option_Menu; declared in MainActivity
// ie; setMenuVisible( true, R.id.action_rescan);
public void setMenuVisible(boolean visible, int id) {
if (option_Menu != null) {
option_Menu.findItem(id).setVisible(visible);
}
}
Mike M. had it, Thank You Mike
added onPrepareOptionsMenu()
added showRescan = visible; and invalidateOptionsMenu(); to setMenuVisible()
all work perfectly now.
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
try {
if( showRescan )
{
option_Menu.findItem(R.id.action_rescan).setVisible( true );
} else
{
option_Menu.findItem(R.id.action_rescan).setVisible( false );
}
}
catch(Exception e) {
Log.e(TAG, "onPrepareOptionsMenu error");
}
return true;
}
// when task is completed you can show your menu just by calling this method
// remember to run on main thread
// ie; setMenuVisible( true, R.id.action_rescan);
public void setMenuVisible(boolean visible, int id) {
if (option_Menu != null) {
option_Menu.findItem(id).setVisible(visible);
showRescan = visible;
invalidateOptionsMenu();
}
}
My use case is:
tap on the screen and save the "point" as starting anchor
tap on the screen second time and save the "point" as end anchor
push the button that will move the object from starting to end anchor
I've built my own node that is using ObjectAnimator similar like in the solar system example. My only problem is that I do not know how to determine start and end point for the the evaluator. My first thought was to take the x,y,z from Pose of start and end anchor
Vector3 start = new Vector3(startAnchor.getPose().tx(), startAnchor.getPose().ty(), startAnchor.getPose().tz());
Vector3 end = new Vector3(endAnchor.getPose().tx(), endAnchor.getPose().ty(), endAnchor.getPose().tz());
…
movingAnimation.setObjectValues(startingPoint, endPoint);
movingAnimation.setPropertyName("localPosition");
movingAnimation.setEvaluator(new Vector3Evaluator());
but when I do that animation is done from completely different places.
I haven't found any reference to built-in tools for such operation.
I'm using Sceneform.
So the question is: How to make a fluent animation (a simple slide is enough) from anchor A to anchor B?
I did this in the HelloSceneform sample. I created the first AnchorNode and added the "andy" node as a child. On the next tap, I created the endPosition AnchorNode and started the animation to move to that position.
The thing to remember is that if you are using the positions of objects with a different parent, you want to use worldPosition vs. localPosition.
private void onPlaneTap(HitResult hitResult, Plane plane, MotionEvent motionEvent) {
if (andyRenderable == null) {
return;
}
// Create the Anchor.
Anchor anchor = hitResult.createAnchor();
// Create the starting position.
if (startNode == null) {
startNode = new AnchorNode(anchor);
startNode.setParent(arFragment.getArSceneView().getScene());
// Create the transformable andy and add it to the anchor.
andy = new Node();
andy.setParent(startNode);
andy.setRenderable(andyRenderable);
} else {
// Create the end position and start the animation.
endNode = new AnchorNode(anchor);
endNode.setParent(arFragment.getArSceneView().getScene());
startWalking();
}
}
private void startWalking() {
objectAnimation = new ObjectAnimator();
objectAnimation.setAutoCancel(true);
objectAnimation.setTarget(andy);
// All the positions should be world positions
// The first position is the start, and the second is the end.
objectAnimation.setObjectValues(andy.getWorldPosition(), endNode.getWorldPosition());
// Use setWorldPosition to position andy.
objectAnimation.setPropertyName("worldPosition");
// The Vector3Evaluator is used to evaluator 2 vector3 and return the next
// vector3. The default is to use lerp.
objectAnimation.setEvaluator(new Vector3Evaluator());
// This makes the animation linear (smooth and uniform).
objectAnimation.setInterpolator(new LinearInterpolator());
// Duration in ms of the animation.
objectAnimation.setDuration(500);
objectAnimation.start();
}
/**
* This is an example activity that uses the Sceneform UX package to make common AR tasks easier.
*/
public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName();
private static final double MIN_OPENGL_VERSION = 3.1;
Session mSession;
private ArFragment arFragment;
private ArSceneView arSceneView;
private ModelRenderable andyRenderable;
private boolean shouldConfigureSession = false;
private boolean modelAdded = false;
private ObjectAnimator objectAnimation;
private TransformableNode andy;
private AnchorNode endNode;
private GestureDetector trackableGestureDetector;
/**
* Returns false and displays an error message if Sceneform can not run, true if Sceneform can run
* on this device.
* <p>
* <p>Sceneform requires Android N on the device as well as OpenGL 3.1 capabilities.
* <p>
* <p>Finishes the activity if Sceneform can not run
*/
public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
if (Build.VERSION.SDK_INT < VERSION_CODES.N) {
Log.e(TAG, "Sceneform requires Android N or later");
Toast.makeText(activity, "Sceneform requires Android N or later", Toast.LENGTH_LONG).show();
activity.finish();
return false;
}
String openGlVersionString =
((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
.getDeviceConfigurationInfo()
.getGlEsVersion();
if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
Log.e(TAG, "Sceneform requires OpenGL ES 3.1 later");
Toast.makeText(activity, "Sceneform requires OpenGL ES 3.1 or later", Toast.LENGTH_LONG)
.show();
activity.finish();
return false;
}
return true;
}
#Override
#SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"})
// CompletableFuture requires api level 24
// FutureReturnValueIgnored is not valid
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!checkIsSupportedDeviceOrFinish(this)) {
return;
}
setContentView(R.layout.activity_main);
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 105);
arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
if (arFragment != null) {
arFragment.getPlaneDiscoveryController().hide();
arFragment.getPlaneDiscoveryController().setInstructionView(null);
}
arSceneView = arFragment.getArSceneView();
arSceneView.getScene().addOnUpdateListener((this::onUpdateFrame));
arFragment.getArSceneView().getScene().addOnPeekTouchListener(this::handleOnTouch);
this.trackableGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
public boolean onSingleTapUp(MotionEvent e) {
onSingleTap(e);
return true;
}
public boolean onDown(MotionEvent e) {
return true;
}
});
// When you build a Renderable, Sceneform loads its resources in the background while returning
// a CompletableFuture. Call thenAccept(), handle(), or check isDone() before calling get().
File file = new File(Environment.getExternalStorageDirectory(), "model.sfb");
Uri photoURI = Uri.fromFile(file);
Callable callable = () -> (InputStream) new FileInputStream(file);
FutureTask task = new FutureTask<>(callable);
new Thread(task).start();
ModelRenderable.builder()
.setSource(this, R.raw.model) //.setSource(this, callable)
.build()
.thenAccept(renderable -> andyRenderable = renderable)
.exceptionally(
throwable -> {
Toast toast =
Toast.makeText(this, "Unable to load andy renderable", Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return null;
});
arFragment.setOnTapArPlaneListener(
(HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {
if (andyRenderable == null) {
return;
}
if (modelAdded) {
endNode = new AnchorNode(hitResult.createAnchor());
endNode.setParent(arFragment.getArSceneView().getScene());
startWalking();
}
});
}
private void handleOnTouch(HitTestResult hitTestResult, MotionEvent motionEvent) {
// First call ArFragment's listener to handle TransformableNodes.
arFragment.onPeekTouch(hitTestResult, motionEvent);
// Check for touching a Sceneform node
if (hitTestResult.getNode() != null) {
return;
}
// Otherwise call gesture detector.
trackableGestureDetector.onTouchEvent(motionEvent);
}
private void onSingleTap(MotionEvent motionEvent) {
Frame frame = arFragment.getArSceneView().getArFrame();
if (frame != null && motionEvent != null && frame.getCamera().getTrackingState() == TrackingState.TRACKING) {
for (HitResult hit : frame.hitTest(motionEvent)) {
Trackable trackable = hit.getTrackable();
if (trackable instanceof Plane && ((Plane) trackable).isPoseInPolygon(hit.getHitPose())) {
Plane plane = (Plane) trackable;
endNode = new AnchorNode(plane.createAnchor(plane.getCenterPose()));
endNode.setParent(arFragment.getArSceneView().getScene());
startWalking();
// Handle plane hits.
break;
} else if (trackable instanceof Point) {
// Handle point hits
Point point = (Point) trackable;
endNode = new AnchorNode(point.createAnchor(hit.getHitPose()));
endNode.setParent(arFragment.getArSceneView().getScene());
startWalking();
} else if (trackable instanceof AugmentedImage) {
// Handle image hits.
AugmentedImage image = (AugmentedImage) trackable;
endNode = new AnchorNode(image.createAnchor(image.getCenterPose()));
endNode.setParent(arFragment.getArSceneView().getScene());
startWalking();
}
}
}
}
private void startWalking() {
objectAnimation = new ObjectAnimator();
objectAnimation.setAutoCancel(true);
objectAnimation.setTarget(andy);
// All the positions should be world positions
// The first position is the start, and the second is the end.
objectAnimation.setObjectValues(andy.getWorldPosition(), endNode.getWorldPosition());
// Use setWorldPosition to position andy.
objectAnimation.setPropertyName("worldPosition");
// The Vector3Evaluator is used to evaluator 2 vector3 and return the next
// vector3. The default is to use lerp.
objectAnimation.setEvaluator(new Vector3Evaluator());
// This makes the animation linear (smooth and uniform).
objectAnimation.setInterpolator(new LinearInterpolator());
// Duration in ms of the animation.
objectAnimation.setDuration(500);
objectAnimation.start();
}
private void configureSession() {
Config config = new Config(mSession);
if (!setupAugmentedImageDb(config)) {
Toast.makeText(this, "Could not setup augmented", Toast.LENGTH_SHORT).show();
}
config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
mSession.configure(config);
}
#Override
public void onPause() {
super.onPause();
if (mSession != null) {
// Note that the order matters - GLSurfaceView is paused first so that it does not try
// to query the session. If Session is paused before GLSurfaceView, GLSurfaceView may
// still call session.update() and get a SessionPausedException.
arSceneView.pause();
mSession.pause();
}
}
#Override
protected void onResume() {
super.onResume();
if (mSession == null) {
String message = null;
Exception exception = null;
try {
mSession = new Session(this);
} catch (UnavailableArcoreNotInstalledException
e) {
message = "Please install ARCore";
exception = e;
} catch (UnavailableApkTooOldException e) {
message = "Please update ARCore";
exception = e;
} catch (UnavailableSdkTooOldException e) {
message = "Please update this app";
exception = e;
} catch (Exception e) {
message = "This device does not support AR";
exception = e;
}
if (message != null) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Exception creating session", exception);
return;
}
shouldConfigureSession = true;
}
if (shouldConfigureSession) {
configureSession();
shouldConfigureSession = false;
arSceneView.setupSession(mSession);
}
}
private void onUpdateFrame(FrameTime frameTime) {
Frame frame = arSceneView.getArFrame();
Collection<AugmentedImage> updatedAugmentedImages =
frame.getUpdatedTrackables(AugmentedImage.class);
Log.d("size----", String.valueOf(updatedAugmentedImages.size()));
for (AugmentedImage augmentedImage : updatedAugmentedImages) {
if (augmentedImage.getTrackingState() == TrackingState.TRACKING) {
// Check camera image matches our reference image
if (augmentedImage.getName().contains("car")) {
if (!modelAdded) {
modelAdded = true;
Anchor anchor = augmentedImage.createAnchor(augmentedImage.getCenterPose());
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
// Create the transformable andy and add it to the anchor.
andy = new TransformableNode(arFragment.getTransformationSystem());
andy.setParent(anchorNode);
andy.setRenderable(andyRenderable);
andy.select();
}
}
}
}
}
private boolean setupAugmentedImageDb(Config config) {
AugmentedImageDatabase augmentedImageDatabase;
Bitmap augmentedImageBitmap = loadAugmentedImage();
if (augmentedImageBitmap == null) {
return false;
}
augmentedImageDatabase = new AugmentedImageDatabase(mSession);
augmentedImageDatabase.addImage("car", augmentedImageBitmap);
config.setAugmentedImageDatabase(augmentedImageDatabase);
return true;
}
private Bitmap loadAugmentedImage() {
try (InputStream is = getAssets().open("car.jpeg")) {
return BitmapFactory.decodeStream(is);
} catch (IOException e) {
Log.e(TAG, "IO exception loading augmented image bitmap.", e);
}
return null;
}
}
I have two objects, a establishment object that belongs to a deal object that can be voted upon. If I up/down vote the same deal multiple times, the seventh time I vote the query just sits and does not do anything. The app does not crash, but it also does not save. If I go into another activity that requires a parse.com query that query also will not work. Here is my up vote logic (down voting is identical).
Assume all vars used are initialized before onCreate().
Are my queries getting backed up in a pipe somewhere?
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
upVoteButton = (Button) findViewById(R.id.deal_up_vote_button);
upVoteButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
new UpVoteTask().execute();
}
});
}
// visually changes buttons if they are selected
private void setButtons(Boolean queryDb) {
if (queryDb == true) {
queryParse();
}
// if deal found correctly
if (deal != null) {
// if user found correctly
if (dealVoteUser != null) {
if (dealVoteUser.get("vote").toString().equals("0")) {
upVoteButton.setPressed(false);
downVoteButton.setPressed(true);
} else if (dealVoteUser.get("vote").toString().equals("1")) {
upVoteButton.setPressed(true);
downVoteButton.setPressed(false);
} else if (dealVoteUser.get("vote").toString().equals("2")) {
upVoteButton.setPressed(false);
downVoteButton.setPressed(false);
}
}
}
}
// queries parse and populates vars
private void queryParse(){
ParseQuery<ParseObject> queryDeal = ParseQuery.getQuery("Deal");
queryDeal.whereEqualTo("objectId", deal_id);
try {
deal = queryDeal.getFirst();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ParseQuery<ParseObject> queryDealVoteUser = ParseQuery
.getQuery("deal_vote_users");
queryDealVoteUser.whereEqualTo("deal", deal).whereEqualTo("user",
ParseUser.getCurrentUser());
try {
dealVoteUser = queryDealVoteUser.getFirst();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// UpVoteTask AsyncTask
private class UpVoteTask extends AsyncTask<Void, Void, Void> {
#Override
protected void onPreExecute() {
super.onPreExecute();
// Create a progressdialog
if(upVoteProgressDialog != null){
upVoteProgressDialog.dismiss();
upVoteProgressDialog = null;
}
upVoteProgressDialog = new ProgressDialog(DealsDetailsActivity.this);
// Set progressdialog message
upVoteProgressDialog.setMessage("Saving...");
upVoteProgressDialog.setIndeterminate(false);
// Show progressdialog
upVoteProgressDialog.show();
}
#Override
protected Void doInBackground(Void... params) {
queryParse();
// if deal found correctly
if (deal != null) {
// if user has not voted yet
if (dealVoteUser == null) {
// create new and assign vote to 1
dealVoteUser = new ParseObject("deal_vote_users");
dealVoteUser.put("deal", deal);
dealVoteUser.put("user", ParseUser.getCurrentUser());
dealVoteUser.put("vote", 1);
up_votes = deal.getInt("up_votes") + 1;
down_votes = deal.getInt("down_votes");
// if user already down voted
} else if (dealVoteUser.get("vote").toString().equals("0")) {
// change vote to 1
dealVoteUser.put("vote", 1);
up_votes = deal.getInt("up_votes") + 1;
down_votes = deal.getInt("down_votes") - 1;
// if user already up voted
} else if (dealVoteUser.get("vote").toString().equals("1")) {
// already voted up, remove vote
dealVoteUser.put("vote", 2);
up_votes = deal.getInt("up_votes") - 1;
down_votes = deal.getInt("down_votes");
// if user already voted but cleared vote
} else if (dealVoteUser.get("vote").toString().equals("2")) {
// change vote to 1
dealVoteUser.put("vote", 1);
up_votes = deal.getInt("up_votes") + 1;
down_votes = deal.getInt("down_votes");
}
// calculate overall rating percentage
if ((up_votes + down_votes) != 0) {
rating = (up_votes / (up_votes + down_votes)) * 100;
} else if ((up_votes == 0) && (down_votes == 0)) {
rating = 0;
} else {
rating = 50;
}
deal.put("rating", rating);
deal.put("up_votes", up_votes);
try {
deal.save();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
dealVoteUser.save();
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
// deal not found problem
}
return null;
}
#Override
protected void onPostExecute(Void result) {
// visually change buttons without querying db
setButtons(false);
//remove progress dialogue
if(upVoteProgressDialog != null){
upVoteProgressDialog.dismiss();
upVoteProgressDialog = null;
}
}
}
Use the saveInBackground method - it will do the same as save, but also save it to your application's cache so that you won't get different values while the data is being saved, so it won't have any apparent effect on your application. It's the best method to save or find (it has a 'sister' method named findInBackground). It acts like an Async task and does not clog your main thread.
I switched all parse calls over to ._____InBackground() and I moved the save logic to onPause(). This way I am not making multiple save calls to parse if the user decides to change their vote multiple times.
i am using check box for saving data in database .if it is checked then app redirecting to other screen by saving data after that if i click on device back button then app showing it is not checked.how can i fix this issue?
here i am placing code
public void joinLisn(){
String shareProfileType2=Constants.PROFILE_SHARE_ALL;
String accessToken = null;
DatabaseHelper helper = new DatabaseHelper(getApplicationContext());
DatabaseUtility dao = new DatabaseUtility(helper);
try {
accessToken = dao.getAccessToken();
} catch (Exception e1) {
handler.sendEmptyMessage(1);
return;
}
if(accessToken == null || accessToken.length() == 0){
handler.sendEmptyMessage(1);
return;
}
Map<String , String> params = new HashMap<String,String>();
params.put(Constants.ACCESS_TOKEN_PARAM, accessToken);
params.put(Constants.LISN_ID_PARAM, id);
params.put(Constants.PROFILE_TYPE_PARAM,shareProfileType2);
Status status = null;
try {
status = Utils.joinLisn(params, this);
} catch (NullPointerException e) {
handler.sendEmptyMessage(12);
return;
} catch (JSONException e) {
handler.sendEmptyMessage(11);
return;
}
if(status == null){
handler.sendEmptyMessage(1);
} else if(status.getStatus().equalsIgnoreCase(Constants.SUCCESS)){
try {
Intent lisnDetailIntent = new Intent(this, LisnDetailTabView.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle bundleObj = new Bundle();
bundleObj.putString("id", id);
bundleObj.putString("RSVP","In");
lisnDetailIntent.putExtras(bundleObj);
startActivityForResult(lisnDetailIntent,0);
overridePendingTransition(android.R.anim.slide_in_left, android.R.anim.slide_out_right);
handler.sendEmptyMessage(8);
} catch(Exception ex) {}
} else{
handler.sendEmptyMessage(2);
return;
}
}
Override the onbackpressed to trigger your function to save the states.
public void onBackPressed() {
//Do your db saving here
super.onBackPressed();
}
If your app is redirecting to other app, your app will be put to background. Make use of onSaveInstanceState and onRestoreInstanceState to save and restore the checkbox state.
I am trying to lock my screen in whatever orientation the user is in when the application launches a dialog and then unlocking it when the dialog dismisses. Here is my lock and unlock code:
// Sets screen rotation as fixed to current rotation setting
private void mLockScreenRotation() {
Log.d("####################", "screen orientation is " + mContext.getResources().getConfiguration().orientation);
// Stop the screen orientation changing during an event
if (mContext.getResources().getConfiguration().orientation == 1)
((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
else ((Activity) mContext).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// switch (mContext.getResources().getConfiguration().orientation)
// {
// case Configuration.ORIENTATION_PORTRAIT:
// ((Activity) mContext).setRequestedOrientation(
// ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
// break;
// case Configuration.ORIENTATION_LANDSCAPE:
// ((Activity) mContext).setRequestedOrientation(
// ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// break;
// }
}
// allow screen rotations again
private void mUnLockScreenRotation() {
this.setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
mIsScreenRotationLocked = false;
}
I call mLockScreenRotation() when I launch any dialogs and I call mUnlockScreenRotation() in my handler and in my DialogInterface.OnClickListener's.
Sometimes my screen remains locked, but it is not consistent. Any suggestions or ideas why or how to handle this?
Thanks in advance for any help!
Ammendment: code where I am locking my screen:
public void displayProgressDialog(){
mLockScreenRotation();
// Get local handle on class progress dialog for optimization purposes
ProgressDialog temp = mProgressDialog = new ProgressDialog(this);
// Get message string (for some reason this dialog can't handle res IDs for messages)
String message = getString(R.string.downloading);
// Set some paramaters
temp.setIndeterminate(true);
temp.setTitle(R.string.weather_data);
temp.setMessage(message);
temp.setCancelable(false);
temp.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.MEMORY_TYPE_PUSH_BUFFERS /*WindowManager.LayoutParams.FLAG_BLUR_BEHIND*/);
temp.show();
}
public void displayLocationSearchDialog(){
mLockScreenRotation();
// Get local handle on class progress dialog for optimization purposes
ProgressDialog temp = mCoordinateSearchDialog = new ProgressDialog(this);
// Get message string (for some reason this dialog can't handle res IDs for messages)
String message = getString(R.string.searching);
// Set some paramaters
temp.setIndeterminate(true);
temp.setTitle(R.string.location_search);
temp.setMessage(message);
temp.setCancelable(false);
temp.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
temp.show();
}
public void showDatafeedFailedDialog(){
mLockScreenRotation();
new AlertDialog.Builder(this)
.setTitle(R.string.network_error)
.setMessage(R.string.weather_data_failed)
.setPositiveButton(R.string.try_again, mTryAgainListener)
.setNegativeButton(R.string.dismiss, null)
.create()
.show();
}
public void showCoordinateSearchFailedDialog(){
mLockScreenRotation();
new AlertDialog.Builder(this)
.setTitle(R.string.network_error)
.setMessage(R.string.location_search_failed)
.setPositiveButton(R.string.try_again, mCoordTryAgainListener)
.setNegativeButton(R.string.dismiss, null)
.create()
.show();
}
private void showGpsAlertDialog(){
mLockScreenRotation();
new AlertDialog.Builder(this)
.setTitle(R.string.gps_error)
.setMessage(R.string.gps_error_details)
.setNeutralButton(R.string.dismiss, null)
.setPositiveButton(R.string.go_to_settings, mToSettingsListener)
.create()
.show();
}
private void showGpsSearchingDialog(){
mLockScreenRotation();
ProgressDialog temp = mGpsSearchAlertDialog = new ProgressDialog(this);
String message = getString(R.string.location_services_details);
String btnText = getString(R.string.cancel);
temp.setIndeterminate(true);
temp.setTitle(R.string.location_services);
temp.setMessage(message);
temp.setButton(btnText, mCancelGpsSearchListener);
temp.setCancelable(true);
temp.getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
temp.show();
}
private void showGpsTimeoutAlertDialog(){
mLockScreenRotation();
new AlertDialog.Builder(this)
.setTitle(R.string.gps_error)
.setMessage(R.string.gps_timeout_message)
.setPositiveButton(R.string.try_again, mGpsTimeoutListener)
.setNegativeButton(R.string.dismiss, mGpsTimeoutListener) // check this line with free if still no good
.create()
.show();
}
private void showWeatherAlertDialog(){
Log.d("############", "weather alert dialog");
mLockScreenRotation();
String message = null;
if(mWD.getWarningTypes() == null) return;
int cnt = 0;
int size = mWD.getWarningTypes().size() - 1;
for(String warningType : mWD.getWarningTypes()){
if(cnt == 0) message = warningType;
else if(cnt == size) message += " and " + warningType;
else message += ", " + warningType;
cnt++;
}
new AlertDialog.Builder(this)
.setTitle(R.string.watches_and_warnings)
.setMessage(message)
.setPositiveButton(R.string.go_to_accuweather, mToAlertWebListener)
.setNeutralButton(R.string.dismiss, null)
.create()
.show();
}
private void showNeedLocationAlertDialog() {
mLockScreenRotation();
new AlertDialog.Builder(this).setTitle(R.string.error).setMessage(
R.string.add_location).setNeutralButton(R.string.dismiss, null)
.setPositiveButton(R.string.okay, mToLocationSearchListener)
.create().show();
}
private void showConnectivityAlertDialog() {
mLockScreenRotation();
new AlertDialog.Builder(this).setTitle(R.string.network_error)
.setMessage(R.string.no_connection).setNeutralButton(
R.string.dismiss, null).create().show();
}
private void showCurrentUrlInBrowser(){
// Show current conditions web page
if(mWD.getURL() == null || mWD.getURL().length()
This is a bad solution, but it works. Tested on LG GT540(Android 2.3.7) and Asus Transformer(Android 3.2):
private void stopRotate()
{
if(getResources().getConfiguration().orientation == 1)
{
if( display.getOrientation() == 1 || display.getOrientation() == 2)
setRequestedOrientation(9);
else
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
else
{
if( display.getOrientation() == 2 || display.getOrientation() == 3)
setRequestedOrientation(8);
else
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
}
private void startRotate()
{
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
Instead of putting the call to change orientation within the dialog (and then presumably dismissing said dialog immediately afterwards), try implementing onDismiss listener to your Dialog, as outlined here.