Thread not terminating correctly, I think - android

public String newUser = "false";
public double lat = 0.0, lon = 0.0;
I have the following function in my android app (called when a Button is clicked) which starts a thread:
public void SignUpFunction(View view) {
assignValues();
String filledAll = checkIfFilled();
if (filledAll.equals("true")) {
Log.d("LIFECYCLE", "calling thread..");
//my thread
new validateThread().start();
Log.d("After thread start","This log call does not occur");
if (newUser.equals("true")) {
Toast.makeText(this, "Please wait as we obtain your location", Toast.LENGTH_SHORT).show();
getMyLocationFunction();
} else {
return;
}
}
}
validateThread:
class validateThread extends Thread {
public void run() {
Log.d("LIFECYCLE", "validateThread entered...");
try {
newUser = "true";
Log.d("validateThread", "Validated and found new user");
} catch (Exception e) {
Log.d("validateThread", "Exception in validateThread: " + e.getMessage());
}
}
}
The thread runs correctly...but after the last line, it does not go back to its point of start. I don't understand why this is happening because I've used threads before and they all work correctly.
I know I can just give the getMyLocation function inside the thread but I really need it this way.
I've searched for similar questions but none helped.. What am I doing wrong here?
Thanks in advance.

It's a race. SignUpFunction should wait until validateThread decides whether or not to set newUser = "true". Even with the race your code may work sometimes, but that is by accident.

Related

Settings.canDrawOverlays is returning false even after turning the permission on from settings

I am trying billow Code from this answer to check if the permission is enabled. but it is returning false even when the permission is enabled from the settings.
public static boolean canDrawOverlayViews(Context con){
if(Build.VERSION.SDK_INT< Build.VERSION_CODES.LOLLIPOP){return true;}
try {
return Settings.canDrawOverlays(con);
}
catch(NoSuchMethodError e){
return canDrawOverlaysUsingReflection(con);
}
}
public static boolean canDrawOverlaysUsingReflection(Context context) {
try {
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
Class clazz = AppOpsManager.class;
Method dispatchMethod = clazz.getMethod("checkOp", new Class[] { int.class, int.class, String.class });
//AppOpsManager.OP_SYSTEM_ALERT_WINDOW = 24
int mode = (Integer) dispatchMethod.invoke(manager, new Object[] { 24, Binder.getCallingUid(), context.getApplicationContext().getPackageName() });
return AppOpsManager.MODE_ALLOWED == mode;
} catch (Exception e) { return false; }
}
Recently I've also faced the same issue and got the following workaround .
Referenced from
https://code.google.com/p/android/issues/detail?id=198671#c7
public boolean getWindoOverLayAddedOrNot2() {
String sClassName = "android.provider.Settings";
try {
Class classToInvestigate = Class.forName(sClassName);
if (context == null)
context = activity;
Method method = classToInvestigate.getDeclaredMethod("isCallingPackageAllowedToDrawOverlays", Context.class, int.class, String.class, boolean.class);
Object value = method.invoke(null, context, Process.myUid(), context.getPackageName(), false);
Log.i("Tag", value.toString());
// Dynamically do stuff with this class
// List constructors, fields, methods, etc.
} catch (ClassNotFoundException e) {
// Class not found!
} catch (Exception e) {
// Unknown exception
e.printStackTrace();
}
return false;
}
does the check involves the device admin?
I have encountered this problem when disabling device admin, I have checked this permission in the DeviceAdminReceiver->onDisabled() and on some devices, and canDrawOverlays returned false, despite the fact i had the permission.
The above answer helped sometimes but not all the time. the thing that did work is Thread.sleep before the check.
try {
Thread.sleep(20);
} catch (InterruptedException e) {
// some exception here
}
The minimal time that worked for me was 20 millis. than canDrawOverlays returned true
Note: this is not a good practice however this is the only thing that worked for me
Based on BennyP's answer, I've made a Runnable run the required code after 500ms and that worked very well. The feedback is a bit delayed, but the user won't even notice the delay.
This is the code I've added to my onResume()
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(!Settings.canDrawOverlays(ControllerActivity.this)){
//Handle overlay permission not given here
}
else{
//Handle overlay permission given here
}
}
}, 500);
Hope it helps!
I tried restarting the activity after the user accessed the setting . This is code :
public static void restartActivity(Activity act){
Intent intent = getIntent();
finish();
startActivity(intent);
}
First of all, I am really very surprised with this strange behaviour of
Settings.canDrawOverlays(this);
I also faced the same issue with its usage, it was returning false even if the permission is already assigned.
What I noticed that, I was using this check in my onStart() method, where it was creating this wired behavior. To resolve this, I searched over internet and no result was there that can satisfy me and the one I can use.
Solution
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Log.e("Overlay Permission", "" + Settings.canDrawOverlays(this));
if (!Settings.canDrawOverlays(this)) {
MyPreferences.saveBoolean(HomeScreen.this, "showOverlayPermissionDialog", true);
} else {
MyPreferences.saveBoolean(HomeScreen.this, "showOverlayPermissionDialog", false);
}
}
I did something lake this, in my onCreate(). Here I saved the values accordingly in my SharedPreferences, and according to these Shared Preference values, I created a check for showing an overlay dialog in my onStart(). This worked fine!
You can try this solution, and mark this answer useful if your problem is solved.
Thanks

Android Mocking GPS Location avoid detection of ALLOW_MOCK_LOCATION as true by other app

Im making an apps that mock location and executing set ALLOW_MOCK_LOCATION turned on and off on runtime, so i hopes the other apps which detecting the ALLOW_MOCK_LOCATION flag will never get the ALLOW_MOCK_LOCATION as 1(true).
I read from here that it was possible and said to be fast enough, so other apps can hardly detect the change of ALLOW_MOCK_LOCATION. But what i am get is the other apps still sometimes reed ALLOW_MOCK_LOCATION as 1(true).
Please note that my devices already rooted and i can confirm it does mocked the location well. I also tried move it into /system/app, but still also encounter this problem.
This is the periodical loop which dispatch a asyntask with timeout(I even set the timeout 3 millis !!).
while(RUNNING){
fakeLocation.setAltitude(65.0);
fakeLocation.setAccuracy(Criteria.ACCURACY_FINE);
fakeLocation.setSpeed(0.0f);
fakeLocation.setTime(System.currentTimeMillis());
if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
fakeLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
if(locationJellyBeanFixMethod!=null){
try {
locationJellyBeanFixMethod.invoke(fakeLocation);
}catch(Exception ex){}
}
}
new Thread(new Runnable() {
#Override
public void run() {
try {
new MockTask().execute().get(3, TimeUnit.MILLISECONDS);
}catch(TimeoutException e){
changeMockLocationSettings(0);
//Log.d(GLOBAL_VAR.TAG_DEBUG,"Mock location timeout:");
}catch(Exception e){}
}
}).start();
try {Thread.sleep(1500);} catch (InterruptedException e) {}
}
Below is the Asyntask
private class MockTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... param) {
try {
changeMockLocationSettings(1);
locationManager.setTestProviderLocation(GLOBAL_VAR.PROVIDER_NAME, fakeLocation);
changeMockLocationSettings(0);
//Log.d(GLOBAL_VAR.TAG_DEBUG,"location mocked -> "+fakeLocation);
} catch (Exception ex) {
//Log.d(GLOBAL_VAR.TAG_DEBUG,"Failed to mock location:"+ex.toString());
}
return null;
}
#Override
protected void onPostExecute(Void loc) {}
}
And lastly, the method to change ALLOW_MOCK_LOCATION
private boolean changeMockLocationSettings(int value) {
try {
return Settings.Secure.putInt(getApplicationContext().getContentResolver(),Settings.Secure.ALLOW_MOCK_LOCATION, value);
} catch (Exception e) {
Log.d(GLOBAL_VAR.TAG_DEBUG,"Setting allow mock location to "+value+" failed :"+e.toString());
e.printStackTrace();
return false;
}
}
Please help and correct me, and even suggest a better solution if any, and thanks in Advance

Android not waiting for DB response before finishing statement

I have an interesting problem that I've never run into in programming before. I have an onClickListener that does a lot of username and password checks (makes sure the username is proper length, not taken, etc). I'm using MobDB, and I was using a conditional statement that would return a row if the username already existed. The problem is that the Listener skips the DB and goes to the final check that, if everything works, posts a new username and password to my DB. How can I make it wait for a response from the DB before skipping to the last check?
Here is the relevant code:
usernamecheck3 = true;
MobDB.getInstance().execute(APP_KEY, null, rd, null, false, new MobDBResponseListener() {
#Override public void mobDBSuccessResponse() {
usernamecheck3 = false;
Log.e("mobdbSuccess:", "success");
}
#Override public void mobDBResponse(Vector<HashMap<String, Object[]>> row) {
}
#Override public void mobDBResponse(String jsonObj) {
/*Log.e("mobdbSuccess:", "jsonObj");
Log.e("mobdbSuccess:", jsonObj);
JSONObject mainObject;
try {
mainObject = new JSONObject(jsonObj);
// need to parse the json object.
} catch (JSONException e1) {
e1.printStackTrace();
} */
}
#Override public void mobDBFileResponse(String fileName, byte[] fileData) {
//get file name with extension and file byte array
}
#Override public void mobDBErrorResponse(Integer errValue, String errMsg) {
usernamecheck3 = false;
Log.e("doesnt", "work");
}
});
if(usernamecheck3 == false){
Toast.makeText(getApplicationContext(), "Username is taken, please choose another", Toast.LENGTH_SHORT).show();
}
Basically the check always returns true, and then logcat will say mobdbSuccess: success, which should have set the Bool to false.
Thanks.
MobDBResponseListener is executing on a different thread. What happens here is that the processing is split, while a thread is doing the query, the main thread on which you added the listener, skips right ahead to the validation. Your best bet is to place the validation inside the MobDBResponseListener, on the mobDBResponse method.
Try to debug your code and calls, the Listener may be using an async task. If so, you may do anything you please from the response method, as it will be executing in the main thread again. Otherwise, you should look at solutions that handle threaded execution like Handlers

Android TTS different languages supported each time when checked

I am struggling with one very strange bug in my app.
I have added TTS to it, and I am using the build one. The user can choose the language from the spinner which is filled in during AsyncTask started in onResume().
The AsyncTask looks like this:
private class AsyncTTSDownload extends AsyncTask<Void, Integer, String> {
#Override
protected String doInBackground(Void... params) {
try {
languagesTTS = tts.testLang();
} catch (Exception ex) {
if (D)
Log.e(TAG, ex.toString());
}
return null;
}
#Override
protected void onPostExecute(String result) {
ttsUpdate.dismiss();
TTSSpinnerAdapter adapterTTS = new TTSSpinnerAdapter(
MyTTS.this, android.R.layout.simple_spinner_item,
languagesTTS);
int savedLangTTS = ttsLang.getInt("savedTTS", -1);
langTTS.setAdapter(adapterTTS);
if (savedLangTTS == -1)
{
try {
int langObject = languagesTTS.indexOf(tts.getLanguage());
langTTS.setSelection(langObject);
} catch (IndexOutOfBoundsException ie) {
langTTS.setSelection(0);
}
} else {
langTTS.setSelection(savedLangTTS);
}
Locale langChoosen = (Locale) langTTS.getItemAtPosition(langTTS
.getSelectedItemPosition());
tts.setTTSLanguage(langChoosen);
}
#Override
protected void onPreExecute() {
ttsUpdate = ProgressDialog.show(MyTTS.this, "Wait",
"Loading TTS...");
ttsUpdate.setCancelable(false);
}
}
the thing is, that I am from time to time getting different number of languages supported. This is on this same device, during this same run. Just I open and close Activity with TTS. This bug is causing IndexOutOfBoundsException. This is my way of getting TTS languages:
public List<Locale> testLang() {
Locale[] AvalLoc = Locale.getAvailableLocales();
List<Locale> listaOK = new ArrayList<Locale>();
String tester = "";
for (Locale l : AvalLoc) {
if(tester.contains(l.getLanguage()))
{
continue;
}
int buf = tts.isLanguageAvailable(l);
if (buf == TextToSpeech.LANG_MISSING_DATA
|| buf == TextToSpeech.LANG_NOT_SUPPORTED) {
//TODO maybe
} else {
listaOK.add(l);
tester += l.getLanguage() + ";";
}
}
tts.setLanguage(Locale.ENGLISH);
return listaOK;
}
For now I've only find out a small hack for not showing this error, just save in shared preferences number of languages and compare it with what tts received, but it is not working well at all. Each time I am getting different number.
For me it seems, that something is not finished or started when I am starting again this same activity after return, because this is tts.isAvaliableLanguage(l) who is deciding whether language is supported or not and from time to time, one language is not supported and after reload it is.
EDIT:
As there appeared new comment about my question I need to add one important thing about TTS engine itself.
testLang() is a method inside my class Called TTSClass, that is implementing TextToSpeech.OnInitListener. tts object is created in onCreate of MyTTS activity and this constructor looks like this in TTSClass:
public TTSClass(Context context, Locale language) {
contextTTS = context;
languageTTS = language;
tts = new TextToSpeech(contextTTS, this);
}
and call in activity:
tts = new TTSClass(getApplicationContext(), Locale.ENGLISH);
Because TTSClass implements TextToSpeech.OnInitListener there is also onInit() method which looks like this:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = 0;
result = tts.setLanguage(languageTTS);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
if(D) Log.e(TAG, "This Language is not supported");
}
if(D) Log.d(TAG,"Initialized");
} else {
if(D) Log.e(TAG, "Initilization Failed!");
}
}
So, this is everything connecting to this class and problem I think. If anything is missing, let me now.
EDIT2:
Suggested by shoe rat comment I've run few more tests, and the outcome is just amazing, or extraordinary, I think it is better word.
So what I've done was adding 3 Log from different places in code informing me about list size on different stages.
First was added in onInit() in if status == TextToSpeech.SUCCESS. This one is just simple call of testLang().size(). The outcome is 5 languages - that is the correct number and it is always like this, no matter if there is or isn't an exception.
Second was added there:
protected String doInBackground(Void... params) {
try {
Log.w(TAG,"before: "+tts.testLang().size());
languagesTTS = tts.testLang();
}
and this one is starting to act quite weird. It is sometimes, or even quite often, showing number lower than 5. But this is not the strangest thing.
The third one is just at the beginning of onPostExecute checking the size of languagesTTS. And believe or not, the number is quite often totally different from the second log. However, it is never smaller. It can be equal or bigger.
Does anyone know, what is going one?
I've found solution. It came out that indeed it was initialization problem.
I'm not sure if documentation is saying anything about it, but it seem like the TTS engine initialization is done asynchronously, so it can finish at any time.
My solution was to change the doInBackground() method like this:
#Override
protected String doInBackground(Void... params) {
try {
while(!TTSClass.isInit){}
languagesTTS = tts.testLang();
} catch (Exception ex) {
if (D)
Log.e(TAG, ex.toString());
}
return null;
}
and in onInit() method I've added isInit public static boolean variable:
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
int result = 0;
result = tts.setLanguage(languageTTS);
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
if(D) Log.e(TAG, "This Language is not supported");
}
if(D) Log.d(TAG,"initialized");
isInit = true;
} else {
if(D) Log.e(TAG, "Initilization Failed!");
}
}
Hope, that someone will find it helpful.

How to take a variable's value in the end of the code to use it in the begin of it

I have to post the code to understand what i want to say:
public void répondre()
{
mt = MediaPlayer.create(context,R.raw.ringtone);
mt.setVolume(5,5);
mt.start();
mt.setLooping(true);
//startActivity((new Intent(Intent.ACTION_ANSWER)));
AlertDialog.Builder ad = new AlertDialog.Builder(context);
ad.setTitle("Appel en cours...");
ad.setMessage("Voulez vous répondre à cet appel?");
ad.setPositiveButton("Oui",
new OnClickListener() {
public void onClick(DialogInterface dialog,
int arg1) {
mt.stop();
SipAudioCall incomingCall = null;
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onRinging(SipAudioCall call, SipProfile caller) {
try {
call.answerCall(30);
} catch (Exception e) {
Log.d("Call not answered","Call not answered",e);
}
}
};
SIPCommunicator wtActivity = (SIPCommunicator) context;
incomingCall = wtActivity.manager.takeAudioCall(intent, listener);
incomingCall.answerCall(30);
incomingCall.startAudio();
incomingCall.setSpeakerMode(true);
if(incomingCall.isMuted()) {
incomingCall.toggleMute();
}
wtActivity.call = incomingCall;
String useName = wtActivity.call.getPeerProfile().getDisplayName();
wtActivity.updateStatus("Vous êtes en communication avec " + useName);
} catch (Exception e) {
if (incomingCall != null) {
incomingCall.close();
}
}
}
});
I want to show the caller's name(useName variable) in the AlertDialog. If i put this line(String useName = wtActivity.call.getPeerProfile().getDisplayName();) before MediaPlayerand make ad.setTitle("Appel en cours"+useName); the variable useName is null ! So how doing this ?
Thank you very much.
Fortunatelly, we do not need to break causality as indicated in the question title. Thing is (and that is not something so uncommon with phone applications handling) that in the moment when you get indication about incoming call, caller name is not ready. It is because it takes some time until callers number/uri has to be searched for in the contacts.
So, in order to handle this issue I would suggest that you do one of the following:
indicate incoming call via AlertDialog, but present just caller number/URI. Start Handler and second later update the dialog so it displays name.
when call arrives, start handler and execute your code just second later. Hopefully at that moment Name will be available.
So, in any case you need to update your AlertDialog some safe time after incoming call is indicated.

Categories

Resources