PendingResult<PlaceLikelihoodBuffer> is getting executed for the second time - android

I am trying to make an application where user current place will be messaged to predefined number. I have implemented ShakeDetector library. Everything is working fine but I am getting the place name for the second time when I am shaking the device. [Please see the screenshots]
I put a debug point on the lines on PendingResult part.
For the first time the "for loop" is not executing but when I am shaking it for the second time the for loop is executing and I am getting the places. Whats wrong? Does PendingResult work as asynctask in android?
PS: I faced the similar problem while I was working with Google Fit API.the PendingResult was getting executed when I am returning to previous activity by pressing back button.I resolved the issue by creating different fragments and providing single GoogleApiClient to each of them.But as you can guess there is no scope of this here. What should I do plz help.
here is my code of the PhoneService.java where everything is happening.
public class PhoneService extends Service implements GoogleApiClient.OnConnectionFailedListener,GoogleApiClient.ConnectionCallbacks {
GoogleApiClient googleApiClient;
String place="";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
ShakeDetector.create(this, new ShakeDetector.OnShakeListener() {
#Override
public void OnShake() {
try{
Toast.makeText(PhoneService.this,"Shake Detected",Toast.LENGTH_SHORT).show();
buildApiClient();
}catch (SecurityException e){
}
}
});
ShakeDetector.updateConfiguration(3f, 4);
ShakeDetector.start();
Toast.makeText(this,"Service started",Toast.LENGTH_SHORT).show();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
ShakeDetector.stop();
}
public void buildApiClient(){
googleApiClient= new GoogleApiClient
.Builder(this)
.addApi(Places.GEO_DATA_API)
.addApi(Places.PLACE_DETECTION_API)
.addConnectionCallbacks(PhoneService.this)
.addOnConnectionFailedListener(PhoneService.this)
.build();
googleApiClient.connect();
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Toast.makeText(PhoneService.this,"Connected",Toast.LENGTH_SHORT).show();
try{
if(googleApiClient.isConnected()){
PendingResult<PlaceLikelihoodBuffer> result = Places.PlaceDetectionApi
.getCurrentPlace(googleApiClient, null);
result.setResultCallback(new ResultCallback<PlaceLikelihoodBuffer>() {
#Override
public void onResult(PlaceLikelihoodBuffer likelyPlaces) {
for (PlaceLikelihood placeLikelihood : likelyPlaces) {
place=placeLikelihood.getPlace().getName()+"";
Log.d("PLACE",place);
}
likelyPlaces.release();
try{
SmsManager smsManager=SmsManager.getDefault();
smsManager.sendTextMessage("7098027655",null,"I am here at "+place+".Please pick me up.",null,null);
}catch (SecurityException e){
}
}
});
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:7098027655"));
callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(callIntent);
}
}catch (SecurityException e){
}
}
#Override
public void onConnectionSuspended(int i) {
Toast.makeText(PhoneService.this,"Connection Suspended",Toast.LENGTH_SHORT).show();
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Toast.makeText(PhoneService.this,"Connection Failed",Toast.LENGTH_SHORT).show();
}
}

You're creating and connecting a brand new GoogleApiClient every time the user shakes the device. You might have more luck creating and connecting the client once in the service's onCreate() method.

Related

How to run service for always in Android

In my application I want use service for get request to server.
I should run this service for always and not stop it!
I write below code in service, but just show for 5 time and when receive to 5 step. then not show Toast!
But I want always getData() and show Toast.
Service class :
public class NotifyService extends Service {
private static final String TAG = "HelloService";
private boolean isRunning = false;
#Override
public void onCreate() {
Log.i(TAG, "Service onCreate");
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service onStartCommand");
//Creating new thread for my service
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
//Your logic that service will perform will be placed here
//In this example we are just looping and waits for 5000 milliseconds in each loop.
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(5000);
} catch (Exception e) {
}
if (isRunning) {
ExploreSendData sendData = new ExploreSendData();
sendData.setPageIndex(1);
sendData.setPageSize(10);
sendData.setShowFollows(false);
sendData.setShowMovies(true);
sendData.setShowNews(true);
sendData.setShowReplies(false);
sendData.setShowSeries(true);
sendData.setShowSuggestions(false);
InterfaceApi api = ApiClient.getClient().create(InterfaceApi.class);
Call<ExploreResponse> call = api.getExplore(new SharedPrefrencesHandler(NotifyService.this)
.getFromShared(SharedPrefrencesKeys.TOKEN.name()), sendData);
call.enqueue(new Callback<ExploreResponse>() {
#Override
public void onResponse(Call<ExploreResponse> call, Response<ExploreResponse> response) {
if (response.body().getData() != null && response.body().getStatusCode() != 401
&& response.body().getStatusCode() != 402) {
Toast.makeText(NotifyService.this, "Test Show message ever 5second", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ExploreResponse> call, Throwable t) {
}
});
}
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
Log.i(TAG, "Service onBind");
return null;
}
#Override
public void onDestroy() {
isRunning = false;
Log.i(TAG, "Service onDestroy");
}
}
I copy this service code from internet, but just show 5times. I want show always.
How can I edit my codes and fix it? Please help me. Thanks
The problem is not in the service, services start and continue living as long as the app is alive and android doesn't kill it. For an infinite loop replace the "for loop" with "While loop". The below loop doesn't end.
while (true) {
......
......
......
}

iBeacons' background ranging with Altbeacon Library

I need to range beacons on the background using Altbeacons library(work properly on foreground mode)
On my android monitor the log never shows the message for the didRangeBeaconsInRegion method.
On the didEnterRegion, the messages are displayed correctly.
I tried the code below but no success, can any one guide me how to do it?
public class INBeaconApplication extends Application implements BootstrapNotifier, RangeNotifier {
private BeaconManager beaconManager;
private ArrayList<INBeacon> userBeaconArrayList;
private INBeaconUser inBeaconUser;
#Override
public void onCreate() {
super.onCreate();
Log.d("INBeacon", "Application created");
//BeaconManager and custom beaconParser layout
beaconManager = BeaconManager.getInstanceForApplication(this);
beaconManager.getBeaconParsers().clear();
beaconManager.getBeaconParsers().add(new BeaconParser()
.setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
beaconManager.setRegionStatePeristenceEnabled(false);
//Set the BeacomManager background between scan periods
long period = 1000 * 30; //equal to 30 seconds
beaconManager.setBackgroundBetweenScanPeriod(period);
// wake up the app when a beacon is seen
Region region = new Region(Utils.REGION_ID, Identifier
.parse(Utils.INBEACON_UUID), null, null);
new RegionBootstrap(this, region);
new BackgroundPowerSaver(this);
}
boolean checkPermissionForRange(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return getApplicationContext().checkSelfPermission(
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED;
}
return true;
}
#Override
public void didEnterRegion(Region region) {
Log.d("INBeacon", "didEnterRegion");
Utils.sendNotification(this, "Test");
if (checkPermissionForRange()) return;
Log.d("INBeacon", "permissions ok");
try {
beaconManager.startRangingBeaconsInRegion(region);
Log.d("INBeacon","startRanging");
} catch (RemoteException e) {
Log.e("INBeacon",e.getMessage());
}
}
#Override
public void didExitRegion(Region region) {
Log.d("INBeacon", "didExitRegion");
try {
beaconManager.stopRangingBeaconsInRegion(region);
} catch (RemoteException e) {
e.printStackTrace();
}
}
#Override
public void didRangeBeaconsInRegion(Collection<Beacon> collection, Region region) {
Log.d("INBeacon", "didRangeBeaconsInRegion");
ArrayList<Beacon> newBeacons = new ArrayList<>(collection);
.............code to do what i need with the beacons.....
}
It looks like the code simply needs to call:
beaconManager.setRangeNotifier(this);

Bluetooth scanning for devices

I have a problem with my code:
private ScanCallback mLeScanCallback = new ScanCallback(){
//Callback when a BLE advertisement has been found.
#Override
public void onScanResult(int callbackType, final android.bluetooth.le.ScanResult result) {
super.onScanResult(callbackType, result);
new Thread(){
#Override
public void run() {
final BluetoothDevice device = result.getDevice();
runOnUiThread(new Runnable() {
#Override
public void run() {
if (device != null){
mDevices.add(device);
}
}
});
}
}.start();
}
//Callback when batch results are delivered.
#Override
public void onBatchScanResults(List<android.bluetooth.le.ScanResult> results) {
super.onBatchScanResults(results);
}
//Callback when scan could not be started.
#Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
}
currently I am using this code to get the results of my scan. This was based on: https://github.com/RedBearLab/Android/blob/master/Examples/Chat/src/com/redbear/chat/Main.java#L138
The app where is was based on had a lower API level, and my app has a higher one. So I changed it to on startScan() method.
I am honestly stuck, because when I run the app i get no errors. I checked if the mDevices array is empty and it is. Meaning that the code doesn't add the devices to the array or that there aren't any devices to be found by my app specifically.
Any help would be greatly appreciated.
Code of activating scanning
private void scanDevice(){
new Thread() {
#Override
public void run(){
BTScanner.startScan(mLeScanCallback);
try {
Thread.sleep(SCAN_PERIOD);
} catch (InterruptedException e){
e.printStackTrace();
}
BTScanner.stopScan(mLeScanCallback);
}
}.start();
}
Found the problem. It has to do with the permissions for ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION to get the scan results.

Activity isn't finishing if it has called other activities

I have this activity:
public class AMLoginActivity extends Activity implements IAsyncResponse {
public static int finished;
private final String TAG = "AMLoginActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finished = 0;
Intent i = new Intent(AMLoginActivity.this, GDLoginActivity.class);
i.putExtra("response", this);
AMLoginActivity.this.startActivity(i);
}
public void processFinish(){
finished++;
Log.i(TAG, "Number finished: " + finished);
if(finished == 1){
Log.i(TAG, "All finished");
AMLoginActivity.this.finish();
Log.i(TAG, "Finish called");
}
}
Which calls the GDLoginActivity to login to google drive. It can be seen below:
public class GDLoginActivity extends Activity implements GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "GDLoginActivity";
private static final int REQUEST_CODE_RESOLUTION = 3;
private static GoogleApiClient mGoogleApiClient;
#Override
protected void onResume() {
super.onResume();
if (mGoogleApiClient == null) {
// Create the API client and bind it to an instance variable.
// We use this instance as the callback for connection and connection
// failures.
// Since no account name is passed, the user is prompted to choose.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(Drive.API)
.addScope(Drive.SCOPE_FILE)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
Log.i(TAG, "New GDClient created");
}
// Connect the client.
mGoogleApiClient.connect();
}
#Override
protected void onPause() {
if (mGoogleApiClient != null) {
mGoogleApiClient.disconnect();
}
super.onPause();
}
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
IAsyncResponse response = (IAsyncResponse) getIntent().getSerializableExtra("response");
Log.i(TAG, "Process finish");
response.processFinish();
finish();
}
#Override
public void onConnectionSuspended(int cause) {
Log.i(TAG, "GoogleApiClient connection suspended");
}
#Override
public void onConnectionFailed(ConnectionResult result) {
// Called whenever the API client fails to connect.
Log.i(TAG, "GoogleApiClient connection failed: " + result.toString());
if (!result.hasResolution()) {
// show the localized error dialog.
GoogleApiAvailability.getInstance().getErrorDialog(this, result.getErrorCode(), 0).show();
return;
}
// The failure has a resolution. Resolve it.
// Called typically when the app is not yet authorized, and an
// authorization
// dialog is displayed to the user.
try {
result.startResolutionForResult(this, REQUEST_CODE_RESOLUTION);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Exception while starting resolution activity", e);
}
}
public static GoogleApiClient getGoogleApiClient(){
return mGoogleApiClient;
}
}
The issue is that when the GDLoginActivity connects and finish()'s, it should increment finish by 1 and and also finish the AMLoginActivity. It does increment by 1 and call finish() in processFinish(), but nothing happens and AMLoginActivity doesn't actually close (i.e. onDestroy() is never called), so i'm just left with a blank screen. If I remove GDLoginActivity and just call processFinish() instead, then AMLoginActivity finishes just fine, so I assume it has something to do with GDLoginActivity, but this is happening with other similar activities too. Any ideas?
Edit: Also if I hit the back button on the blank screen, then it calls the onDestroy() method of AMLoginActivity and goes to the activity I want, if that hints a clue at what is going on?
It looks like you're finishing them in a weird order. Try finishing the visible activity before you finish the one that started it.
#Override
public void onConnected(Bundle connectionHint) {
Log.i(TAG, "API client connected.");
IAsyncResponse response = (IAsyncResponse) getIntent().getSerializableExtra("response");
Log.i(TAG, "Process finish");
//finishes the previous activity
response.processFinish();
//finishes the visible activity
finish();
//try flipping this order ^
}
You could use startActivitForResult() if you're trying to finish one activity after another has finished.

How to prevent Android displaying app stopped message

Android will kill some service when memory is not enough.
Like this:
I know I can use foreground service to prohibit android to kill my service
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
try {
Notification notification = new Notification(R.mipmap.ic_launcher,"this is service", System.currentTimeMillis());
Intent intent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,intent , 0);
notification.setLatestEventInfo(this, "myapp", "myservice", contentIntent);
notification.flags =Notification.FLAG_AUTO_CANCEL;
startForeground(123,notification);
}
catch(Exception e)
{
stopSelf();
}
}
#Override
public void onDestroy() {
super.onDestroy();
stopForeground(true);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
}
But this will display a notification on screen
I would rather kill service than display notification, but I also don't want to display stopped message.
I found some app, it can display no message when android kills it.
e.g. Screen Dimmer
How can I prohibit android to display app stopped message?
Check this: https://stackoverflow.com/a/32229266/2965799
According to that I have used the following code to handle the exception. I wanted to display another message so I added my own message however if you use his answer there will be no messages.
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
#Override
public void uncaughtException(Thread paramThread, Throwable paramThrowable) {
new Thread() {
#Override
public void run() {
Looper.prepare();
Toast.makeText(getActivity(),"Your message", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
try
{
Thread.sleep(4000); // Let the Toast display before app will get shutdown
}
catch (InterruptedException e) { }
System.exit(2);
}
});
One way is to implement a UncaughtExceptionHandler with your own custom failure code. The API to install your handler is this:
public static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh);
The class is documented here. As a very basic example:
import java.lang.Thread.UncaughtExceptionHandler;
public final class CrashHandler implements UncaughtExceptionHandler {
#Override
public void uncaughtException(Thread thread, Throwable ex) {
android.util.Log.wtf("My app name", "Oops, caught it dying on me!");
}
}
A full working example is available here.

Categories

Resources