Callback method onLocationChanged() is not working on viewmodel - android

I'm trying to get location information in ViewModel.
So I called requestLocationUpdates() by getting LocationManager at View.
I'm not sure requestLocationUpdates() works in viewmodel because callback method onLocationChanged() is not working.
I'm new on android so I don't know what's wrong in here.
Because there was no error on this code.
I guess the error is occuring because callback method onLocationChanged() is not getting called at
ViewModel.
How can make this work??
This is my code.
ViewModel Class
public class MAgencyViewModel extends ViewModel implements LocationListener {
private final String TAG = "MAgencyViewModel";
//이 클래스에서는 Model과 통신하여서 날씨 정보를 받아온다.
private MutableLiveData<ShortWeather> sw;
private MAgencyRepo maRepo;
private GeoInfo gi;
private GpsTransfer gpt;
// public void init(GeoInfo gi) {
// if (sw != null) {
// return;
// }
//
// maRepo = MAgencyRepo.getInStance();
// sw = maRepo.getWeather(gi); // this part is calling a weather api
// Log.i(TAG, "API Connection finish");
// }
public LiveData<ShortWeather> getWeather() {
return sw;
}
#SuppressLint("MissingPermission")
//이부분은 권한 재확인 안하게 해주는 부분이다. 따로 재확인을 안하는 이유는 Activity단에서 이미 확인을 거쳤기 때문이다.
public void locationUpdate(LocationManager lm) {
Log.i(TAG, "locationUpdate()");
// lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0,0,this); //위치정보를 update하는 함수 이건 실제 기기용
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this); //After this nothing is happening
}
//여기서는 이제 위치 정보가 변경 되었을때 진입하는 부분
#Override
public void onLocationChanged(Location location) { //This CallBack method is not working
Log.i(TAG, "onLocationChanged()");
}
//위치 정보 이용 권한 허가를 받지 못했을떄 호출 하는 부분
public void defaultLocation() {
//GpsTransfer 객체 생성
gpt = new GpsTransfer();
//GpsTransfer 위도와 경도를 원주로 설정
gpt.setxLat(76);
gpt.setyLon(122);
gpt.transfer(gpt, 1);
gi = new GeoInfo();
gi.setLon(gpt.getyLon());
gi.setLat(gpt.getxLat());
getTime();
if (sw != null) {
return;
}
//해당 정보를 API를 호출
maRepo = MAgencyRepo.getInStance();
sw = maRepo.getWeather(gi); // this part is calling a weather api
Log.i(TAG, "API Connection finish");
}
public void getTime() {
SimpleDateFormat dateSdf = new SimpleDateFormat("yyyyMMdd"); //년월일 받아오는 부분
SimpleDateFormat timeSdf = new SimpleDateFormat("HH"); //현재시간 받아오는 부분
Calendar cal = Calendar.getInstance(); //현재시간을 받아온다.
gi.setNowDate(dateSdf.format(cal.getTime())); //날짜 세팅
gi.setNowTime(timeSdf.format(cal.getTime())); //시간 세팅
/*
* 하루 전체의 기상예보를 받아오려면 전날 23시에 266개의 날씨정보를 호출해와야 한다.
* 따라서 호출 값은 현재 날짜보다 1일전으로 세팅해줘야 한다.
* */
cal.add(Calendar.DATE, -1); //1일전 날짜를 구하기 위해 현재 날짜에서 -1 시켜주는 부분
gi.setCallDate(dateSdf.format(cal.getTime())); //1일전 값으로 호출값 생성
Log.i(TAG, "DATE : " + gi.getNowDate());
Log.i(TAG, "TIME : " + gi.getNowTime());
Log.i(TAG, "CALL DATE : " + gi.getCallDate());
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}

In you view model
public class MAgencyViewModel extends AndroidViewModel {
private LocationCallback locationCallback;
public boolean requestingLocationUpdates;
public MAgencyViewModel(Application app) {
super(app);
locationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult == null) {
return;
}
for (Location location : locationResult.getLocations()) {
// Update UI with location data
// ...
}
}
};
}
public void startLocationUpdates() {
requestingLocationUpdates = true
LocationServices.getFusedLocationProviderClient(getApplication())
.requestLocationUpdates(locationRequest,
locationCallback,
Looper.getMainLooper());
}
public void stopLocationUpdates() {
requestingLocationUpdates = false
LocationServices.getFusedLocationProviderClient(getApplication())
.removeLocationUpdates(locationCallback);
}
}
Now in your Fragment/Activity override on pause and onresume
Then call the startlocation and stoplction in your viewmodel
#Override
protected void onPause() {
super.onPause();
viewModel.stopLocationUpdates();
}
#Override
protected void onResume() {
super.onResume();
if (viewModel.requestingLocationUpdates) {
startLocationUpdates();
}
Notice setting and checking boolean requestingLocationUpdates if locationRequest is active

Related

Create a background service to collect and send positions

I work on a service that need to be stared/stopped from a specific time, collect user's locations and send them to an API.
I start my service like so
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, CONSTANTES.START_HOURS); //6
calendar.set(Calendar.MINUTE, CONSTANTES.START_MINUTES); //30
calendar.set(Calendar.SECOND, CONSTANTES.START_SECOND);
AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
new Intent(MainActivity.this, AlarmTask.class).setAction("START_SERVICE"), PendingIntent.FLAG_UPDATE_CURRENT);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
alarm.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
} else {
alarm.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
My Receiver
public class AlarmTask extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equalsIgnoreCase("STOP_SERVICE")) {
System.out.println("service : got stop instruction");
if (isMyServiceRunning(context, ScheduleOffsetService.class)) {
context.stopService(new Intent(context, ScheduleOffsetService.class));
}
} else if (intent.getAction().equalsIgnoreCase("START_SERVICE")) {
System.out.println("service : got start instruction");
if (!isMyServiceRunning(context, ScheduleOffsetService.class)) {
context.startService(new Intent(context, ScheduleOffsetService.class));
}
}
}
private boolean isMyServiceRunning(Context context, Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
}
And my service :
public class ScheduleOffsetService extends Service {
private LocationManager mLocationManager;
private ArrayList<Location> locations = new ArrayList<>();
private String token;
public ScheduleOffsetService() {
}
private class LocationListener implements android.location.LocationListener {
Location mLastLocation;
public LocationListener(String provider) {
mLastLocation = new Location(provider);
}
#Override
public void onLocationChanged(Location location) {
System.out.println("Scheduler location : " + location);
mLastLocation.set(location);
locations.add(location);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
LocationListener[] mLocationListeners = new LocationListener[] {
new LocationListener(LocationManager.GPS_PROVIDER),
new LocationListener(LocationManager.NETWORK_PROVIDER)
};
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
stopSelf();
}
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
}
try {
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000 * 60, 10f, mLocationListeners[1]);
} catch (java.lang.SecurityException ex) {
} catch (IllegalArgumentException ex) {
}
try {
mLocationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 1000 * 60, 10f, mLocationListeners[0]);
} catch (java.lang.SecurityException ex) {
} catch (IllegalArgumentException ex) {
}
PropertyApp app = new PropertyApp(this);
System.out.println("ScheduleOffset token : " + app.getToken());
if (app.getToken() != null) {
token = app.getToken();
} else {
stopSelf();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("Scheduler : created");
return START_STICKY;
}
private boolean gpsIsEnable() {
LocationManager manager = (LocationManager) getSystemService(LOCATION_SERVICE);
return manager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}
#Override
public void onDestroy() {
if (mLocationManager != null) {
for (int i = 0; i < mLocationListeners.length; i++) {
try {
mLocationManager.removeUpdates(mLocationListeners[i]);
} catch (Exception ex) {
}
}
}
onEnd();
System.out.println("Scheduler : got destroyed");
super.onDestroy();
}
private void onEnd() {
if (locations.isEmpty()) {
return;
}
Gson gson = new GsonBuilder()
.setLenient()
.create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(/*URL*/)
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
WebServiceInterface webServiceInterface = retrofit.create(WebServiceInterface.class);
JsonObject object = new JsonObject();
for (int i = 0; i < locations.size(); i++) {
JsonObject content = new JsonObject();
content.addProperty("lat", locations.get(i).getLatitude());
content.addProperty("lng", locations.get(i).getLongitude());
Date c = Calendar.getInstance().getTime();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String formattedDate = df.format(c);
content.addProperty("date", formattedDate);
object.add(String.valueOf(i), content);
}
String data = object.toString();
Call<ResponseRetrofitIreby> call = webServiceInterface.jetLagService(token, PropertyApp.PARNTER_ID, data);
call.enqueue(new Callback<ResponseRetrofitIreby>() {
#Override
public void onResponse(Call<ResponseRetrofitIreby> call, Response<ResponseRetrofitIreby> response) {
if (response.isSuccessful()) {
System.out.println("RESPONSE : " + response.body().getTrackingPosition().getErreur());
}
}
#Override
public void onFailure(Call<ResponseRetrofitIreby> call, Throwable t) {
t.printStackTrace();
}
});
}
}
The thing is : When the user asks to be tracked, the listener of my service is no longer called.
Moreover, if the user kill the application the service seems to restart, and thus empty my list of locations.
Can someone, explain me do to ?
you can try this library location tracker background

android : location api asking for wifi

This is weird. I mean, I have strong network, and GPS is turned On, still it asks for Wifi !!
I'm using new Location Api with class FusedLocationProviderClient.
This is how I am checking if Location Settings are enabled or not:
private void checkIfLocationSettingsAreEnabled() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
locationRequest.setInterval(10000);
locationRequest.setFastestInterval(5000);
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(locationRequest);
builder.setAlwaysShow(true);
SettingsClient client = LocationServices.getSettingsClient(context);
Task<LocationSettingsResponse> locationSettingsResponseTask = client.checkLocationSettings(builder.build());
locationSettingsResponseTask.addOnSuccessListener(locationSettingsResponse -> {
getLastKnownLocation();
});
locationSettingsResponseTask.addOnFailureListener(e -> {
if (e instanceof ResolvableApiException) {
myLocationListener.onResolutionNeeded(e);
} else {
myLocationListener.onLocationFailure(e);
}
});
}
With the above code, I am able to get below image:
But then, after clicking OK, again I make call to checkIfSettingsAreEnabled() this shows another popup as below:
I wonder why enabling Wifi is mandatory, even if I am on desert safari, where there is no Wifi to connect to !!
Is there any way to Skip this Wifi option, and work as normal as Google Maps does ?
In fact, Google Maps uses priority PRIORITY_HIGH_ACCURACY and still once, the first settings dialog has been shown, it doesn't ask second time to turn on Wifi.
FusedLocationProvider uses a combo of GPS and WIFI to get your location. Especially when asking for balanced mode, it needs both or won't work (GPS takes power, so it won't rely just on it for balanced). Try max accuracy, its less likely to use it then. Or just use the GPS provider if you actually want GPS.
PRIORITY_BALANCED_POWER_ACCURACY
This priority will go with coarse level accuracy which fetch location only from wi-fi , cellular network or bluetooth and NOT from GPS.
and if device don't have SIM it needs to have wi-fi to get location or it will not call onLocationChanged till won't get location.
With the below solution, I am able to skip this Wifi Settings Dialog. This is not a perfect solution, but just a workaround till I find perfect solution.
Problem was, even after clicking "Ok" on Settings Dialog, it returned result as Activity.RESULT_CANCELLED. Reason was, Wifi was still turned off. So, as a quick fix, made a check in result Activity.RESULT_CANCELLED, that if I could get Location by checking LocationSettingStates.
You can use my MyLocationUtils.java and Base classes LocationActivity.java or LocationFragment.java. Happy Coding..!!
for getting location
MyLocationUtils.java:
public class MyLocationUtils {
public static final int REQUEST_CODE_LOCATION_SETTINGS = 123;
private static final int INTERVAL_IN_MS = 10000;
private static final int FASTEST_INTERVAL_IN_MS = 5000;
private static final int MAX_WAIT_TIME_IN_MS = 5000;
private static final int NUMBER_OF_UPDATES = 1;
private final MyLocationListener myLocationListener;
private final Context context;
private FusedLocationProviderClient mFusedLocationProviderClient;
private LocationCallback mLocationCallback = new LocationCallback() {
#Override
public void onLocationResult(LocationResult locationResult) {
super.onLocationResult(locationResult);
Location location = null;
if (locationResult.getLocations().size() > 0) {
location = locationResult.getLocations().get(0);
}
myLocationListener.onLocationSuccess(location);
stopContinuousLocation();
}
};
public MyLocationUtils(Context context, MyLocationListener myLocationListener) {
this.context = context;
this.myLocationListener = myLocationListener;
initializeFusedLocationProviderClient();
}
private boolean checkIfRequiredLocationSettingsAreEnabled(Context context) {
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
}
private void initializeFusedLocationProviderClient() {
mFusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context);
}
public void stopContinuousLocation() {
mFusedLocationProviderClient.removeLocationUpdates(mLocationCallback);
}
public void getLocation() {
checkIfLocationSettingsAreEnabled();
}
private void checkIfLocationSettingsAreEnabled() {
if (checkIfRequiredLocationSettingsAreEnabled(context)) {
getLastKnownLocation();
} else {
LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder();
builder.addLocationRequest(getLocationRequest());
builder.setAlwaysShow(true);
SettingsClient client = LocationServices.getSettingsClient(context);
Task<LocationSettingsResponse> locationSettingsResponseTask = client.checkLocationSettings(builder.build());
locationSettingsResponseTask.addOnSuccessListener(locationSettingsResponse -> {
// All location settings are satisfied. The client can initialize
// location requests here.
// ...
getLastKnownLocation();
});
locationSettingsResponseTask.addOnFailureListener(e -> {
if (e instanceof ResolvableApiException) {
myLocationListener.onResolutionNeeded(e);
} else {
myLocationListener.onLocationFailure(e);
}
});
}
}
#SuppressLint("MissingPermission")
private void getLastKnownLocation() {
Task<Location> locationTask = mFusedLocationProviderClient.getLastLocation();
locationTask.addOnSuccessListener(location -> {
// Got last known location. In some rare situations this can be null.
if (location != null) {
myLocationListener.onLocationSuccess(location);
} else {
startContinuousLocation();
}
});
locationTask.addOnFailureListener(myLocationListener::onLocationFailure);
}
#SuppressLint("MissingPermission")
private void startContinuousLocation() {
mFusedLocationProviderClient.requestLocationUpdates(getLocationRequest(), mLocationCallback, Looper.getMainLooper())
.addOnFailureListener(myLocationListener::onLocationFailure);
}
private LocationRequest getLocationRequest() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setInterval(INTERVAL_IN_MS);
locationRequest.setFastestInterval(FASTEST_INTERVAL_IN_MS);
locationRequest.setNumUpdates(NUMBER_OF_UPDATES);
locationRequest.setMaxWaitTime(MAX_WAIT_TIME_IN_MS);
return locationRequest;
}
public void resolveLocationSettings(FragmentActivity fragmentActivity, Exception exception) {
ResolvableApiException resolvable = (ResolvableApiException) exception;
try {
resolvable.startResolutionForResult(fragmentActivity, MyLocationUtils.REQUEST_CODE_LOCATION_SETTINGS);
} catch (IntentSender.SendIntentException e1) {
e1.printStackTrace();
}
}
public interface MyLocationListener {
void onLocationSuccess(Location location);
void onResolutionNeeded(Exception exception);
void onLocationFailure(Exception exception);
}
}
BaseLocationActivity.java:
public abstract class LocationActivity extends AppCompatActivity {
private MyLocationUtils myLocationUtils;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myLocationUtils = new MyLocationUtils(this, new MyLocationUtils.MyLocationListener() {
#Override
public void onLocationSuccess(Location location) {
if (shouldBeAllowedToProceed())
LocationActivity.this.onLocationSuccess(location);
}
#Override
public void onResolutionNeeded(Exception exception) {
exception.printStackTrace();
if (shouldBeAllowedToProceed())
LocationActivity.this.onResolutionNeeded(exception);
}
#Override
public void onLocationFailure(Exception exception) {
exception.printStackTrace();
if (shouldBeAllowedToProceed())
LocationActivity.this.onLocationFailure(exception);
}
});
}
protected void getLocation() {
myLocationUtils.getLocation();
}
protected void resolveLocationSettings(Exception exception) {
myLocationUtils.resolveLocationSettings(this, exception);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MyLocationUtils.REQUEST_CODE_LOCATION_SETTINGS) {
final LocationSettingsStates locationSettingsStates = LocationSettingsStates.fromIntent(data);
switch (resultCode) {
case Activity.RESULT_OK:
onResolveLocationSettingOk();
break;
case Activity.RESULT_CANCELED:
// The user was asked to change settings, but chose not to,
// or on Android Oreo 8.1 Wifi Settings were not satisfied inspite of clicking OK, that results on Activity.RESULT_CANCELED
onResolveLocationSettingCancelled(locationSettingsStates);
break;
default:
break;
}
}
}
protected abstract void onResolveLocationSettingOk();
protected void onResolveLocationSettingCancelled(LocationSettingsStates locationSettingsStates) {
if (locationSettingsStates.isLocationPresent() && locationSettingsStates.isLocationUsable()) {
onResolveLocationSettingOk();
}
}
private boolean shouldBeAllowedToProceed() {
return getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED);
}
public abstract void onLocationSuccess(Location location);
public abstract void onResolutionNeeded(Exception exception);
public abstract void onLocationFailure(Exception exception);
#Override
public void onDestroy() {
super.onDestroy();
myLocationUtils.stopContinuousLocation();
}
}
LocationFragment.java:
public abstract class LocationFragment extends Fragment {
private MyLocationUtils myLocationUtils;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
myLocationUtils = new MyLocationUtils(context, new MyLocationUtils.MyLocationListener() {
#Override
public void onLocationSuccess(Location location) {
if (shouldBeAllowedToProceed())
LocationFragment.this.onLocationSuccess(location);
}
#Override
public void onResolutionNeeded(Exception exception) {
exception.printStackTrace();
if (shouldBeAllowedToProceed())
LocationFragment.this.onResolutionNeeded(exception);
}
#Override
public void onLocationFailure(Exception exception) {
exception.printStackTrace();
if (shouldBeAllowedToProceed())
LocationFragment.this.onLocationFailure(exception);
}
});
}
protected void resolveLocationSettings(FragmentActivity appCompatActivity, Exception exception) {
myLocationUtils.resolveLocationSettings(appCompatActivity, exception);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == MyLocationUtils.REQUEST_CODE_LOCATION_SETTINGS) {
final LocationSettingsStates locationSettingsStates = LocationSettingsStates.fromIntent(data);
switch (resultCode) {
case Activity.RESULT_OK:
onResolveLocationSettingOk();
break;
case Activity.RESULT_CANCELED:
// The user was asked to change settings, but chose not to
onResolveLocationSettingCancelled(locationSettingsStates);
break;
default:
break;
}
}
}
protected abstract void onResolveLocationSettingOk();
protected void onResolveLocationSettingCancelled(LocationSettingsStates locationSettingsStates) {
if (locationSettingsStates.isLocationPresent() && locationSettingsStates.isLocationUsable()) {
onResolveLocationSettingOk();
}
}
public void getLocation() {
myLocationUtils.getLocation();
}
private boolean shouldBeAllowedToProceed() {
return getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED);
}
public abstract void onLocationSuccess(Location location);
public abstract void onResolutionNeeded(Exception exception);
public abstract void onLocationFailure(Exception exception);
#Override
public void onDestroy() {
super.onDestroy();
myLocationUtils.stopContinuousLocation();
}
}

Not able to connect to REST API inside a service in some devices

I am using retrofit 1.9 in order to create and use connections with server , its working perfectly in app , but when i am trying to hit api in a service , it is returning me this error
"retrofit.RetrofitError: unexpected end of stream on Connection{, proxy=DIRECT# cipherSuite=none protocol=http/1.1} (recycle count=0)"
and only in some devices like for instance in my Xiaomi Redmi note 3.
Here is my code:-
public class TrackingService extends Service implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private String latitude = "", longitude = "";
private PrefsManager mPrefs;
int requestID = 42;
private int time = 120000;
private static final long SERVICE_INTERVAL = 60000;
private static final long SERVICE_FASTEST = 30000;
private static final long ONE_MIN = 1000;
private GoogleApiClient googleApiClient;
private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
private boolean canGetLocation = false;
private LocationRequest locationRequest;
private LocationManager locationManager;
private final String TAG = "MyAwesomeApp";
private Runnable runnable = new Runnable() {
#Override
public void run() {
updateLocation();
}
};
private Handler handler = new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
getHandler1().postDelayed(runnable, time);
return true;
}
});
private Handler handler1 = new Handler();
public Handler getHandler1() {
return handler1;
}
private NotificationCompat.Builder mBuilder;
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
canGetLocation = !(!locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
}
};
private BroadcastReceiver receiverNetwork = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
time = 5000;
handler.sendMessage(new Message());
}
};
private static API REST_CLIENT;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
registerReceiver(receiverNetwork, new IntentFilter(Constants.NETWORK_BROADCAST));
registerReceiver(receiver, new IntentFilter(Constants.INTENT_LOCATION_SERVICE));
}
private void init() {
mPrefs = new PrefsManager(this);
locationRequest = LocationRequest.create();
locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
locationRequest.setInterval(SERVICE_INTERVAL);
locationRequest.setFastestInterval(SERVICE_FASTEST);
locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
canGetLocation = !(!locationManager
.isProviderEnabled(LocationManager.GPS_PROVIDER) && !locationManager
.isProviderEnabled(LocationManager.NETWORK_PROVIDER));
googleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API).addConnectionCallbacks(this)
.addOnConnectionFailedListener(this).build();
try {
googleApiClient.connect();
} catch (Exception e) {
e.printStackTrace();
}
updateLocation();
}
#Override
public void onDestroy() {
Log.e(TAG, "GPSTrackerNew destroyed!");
googleApiClient.disconnect();
try {
unregisterReceiver(receiverNetwork);
unregisterReceiver(receiver);
} catch (Exception e) {
e.printStackTrace();
}
this.stopForeground(true);
super.onDestroy();
}
/**
* Update driver location for live tracking
*/
private void updateLocation() {
if (canGetLocation()) {
/*setNotification(this, getResources().getString(R.string.tracking));*/
if (!TextUtils.isEmpty(latitude) && !TextUtils.isEmpty(longitude)) {
get().updateLocation(mPrefs.getAccessToken(), latitude, longitude,
new Callback<PojoBase>() {
#Override
public void success(PojoBase pojoBase, Response response) {
try {
if (pojoBase.status == Constants.SUCCESS) {
time = 120000;
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
setNotification(TrackingService.this, getResources().getString(R.string.tracking));
} else if (pojoBase.status == Constants.LOGIN_EXPIRED) {
onDestroy();
}
} catch (Exception e) {
onDestroy();
e.printStackTrace();
}
}
#Override
public void failure(RetrofitError error) {
time = 5000;
setNotification(TrackingService.this, getResources().getString(R.string.network_error));
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
}
});
} else {
time = 5000;
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
}
} else {
time = 5000;
handler.removeCallbacksAndMessages(null);
getHandler1().removeCallbacks(runnable);
handler.sendMessage(new Message());
setNotification(this, getResources().getString(R.string.not_able_to_fetch_location));
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
init();
return START_STICKY;
}
private void setNotification(Context context, String message) {
Intent intent = null;
intent = new Intent(this, HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(context, requestID,
intent, 0);
mBuilder = new NotificationCompat.Builder(context)
.setContentTitle(getResources().getString(R.string.app_name))
.setOngoing(true)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent);
this.startForeground(requestID, mBuilder.build());
}
#Override
public void onConnected(#Nullable Bundle bundle) {
fusedLocationProviderApi.requestLocationUpdates(googleApiClient,
locationRequest, this);
}
#Override
public void onConnectionSuspended(int i) {
Log.i(TAG, "GoogleApiClient connection has been suspend");
}
#Override
public void onLocationChanged(Location location) {
if (location != null) {
Log.i("From service:", "Location received: " + location.toString());
canGetLocation = true;
latitude = String.valueOf(location.getLatitude());
longitude = String.valueOf(location.getLongitude());
} else {
canGetLocation = false;
}
}
public boolean canGetLocation() {
return canGetLocation;
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Log.i(TAG, "GoogleApiClient connection has been failed");
}
public static API get() {
if (REST_CLIENT == null) {
RestAdapter.Builder adapter = new RestAdapter.Builder()
.setClient(new OkClient(getClient()));
adapter.setLogLevel(RestAdapter.LogLevel.BASIC);
adapter.setEndpoint(Constants.ROOT);
RestAdapter mAdapter = adapter.build();
REST_CLIENT = mAdapter.create(API.class);
}
return REST_CLIENT;
}
private static OkHttpClient getClient() {
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(30, TimeUnit.SECONDS);
return client;
}
}
Can anyone tell why is this happening ?
TIA
Try to use execute instead enqueue call.Services is already on different thread. So if you are making a network call on different thread you should run api on same thread.

How to implement mock activity Recognition in android

I am creating a framework which will test the android application. In the android application they have implemented Activity Recognition to know the user activity. I want to test the functionality in a framework. Can anybody tell me how to implement mock activity recognition in android?
Thanks
I would advice you to subclass the ActivityRecognitionClient and reimplement methods which handle registration to updates and take there the reference to the pending intent which calls your subclassed ActivityRecognitionIntentService.
You can then periodically call your service with some artificial data..How to call it? I would just use a thread with handler for its simplicity.
EDIT: I have added a very abstract code snippet which should give you the idea..
public class MainActivity extends FragmentActivity implements
ConnectionCallbacks, OnConnectionFailedListener {
private ActivityRecognitionClient mActivityRecognitionClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
mActivityRecognitionClient = MOCK ? new MockActivityRecognitionClient(getApplicationContext(), this, this) : new ActivityRecognitionClient(getApplicationContext(),
this, this);
}
...
/*
* Called by Location Services once the location client is connected.
*
* Continue by requesting activity updates.
*/
#Override
public void onConnected(Bundle dataBundle) {
/*
* Request activity recognition updates using the preset
* detection interval and PendingIntent. This call is
* synchronous.
*/
mActivityRecognitionClient.requestActivityUpdates(
DETECTION_INTERVAL_MILLISECONDS,
mActivityRecognitionPendingIntent);
/*
* Since the preceding call is synchronous, turn off the
* in progress flag and disconnect the client
*/
mInProgress = false;
mActivityRecognitionClient.disconnect();
}
...
}
/**
* Service that receives ActivityRecognition updates. It receives
* updates in the background, even if the main Activity is not visible.
*/
public class ActivityRecognitionIntentService extends IntentService {
...
/**
* Called when a new activity detection update is available.
*/
#Override
protected void onHandleIntent(Intent intent) {
...
}
...
}
public class MockActivityRecognitionClient extends ActivityRecognitionClient {
private List<ConnectionCallbacks> mConnectionCallbacksList;
private List<OnConnectionFailedListener> mConnectionFailedListenerlist;
private final Handler mHandler;
private long interval = 1000; //default 1000ms
private PendingIntent mPendingIntent;
private Context mContext;
public MockActivityRecognitionClient(Context context, ConnectionCallbacks connectedListener, OnConnectionFailedListener connectionFailedListener) {
super(context, connectedListener, connectionFailedListener);
registerConnectionCallbacks(connectedListener);
registerConnectionFailedListener(connectionFailedListener);
mHandler = new Handler(Looper.getMainLooper());
mContext = context;
}
#Override
public void requestActivityUpdates(long detectionIntervalMillis, PendingIntent callbackIntent) {
interval = detectionIntervalMillis;
mPendingIntent = callbackIntent;
mHandler.postDelayed(postLocationUpdateRunnable, interval);
}
#Override
public void removeActivityUpdates(PendingIntent callbackIntent) {
mHandler.removeCallbacks(postLocationUpdateRunnable);
}
#Override
public void connect() {
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
postConnected();
}
}, 2000);
}
private void postConnected() {
for(ConnectionCallbacks connectionCallbacks : mConnectionCallbacksList){
connectionCallbacks.onConnected(new Bundle()); //insert mocku bundle data
}
}
#Override
public boolean isConnected() {
}
#Override
public boolean isConnecting() {
}
#Override
public void registerConnectionCallbacks(ConnectionCallbacks listener) {
if(mConnectionCallbacksList == null){
mConnectionCallbacksList = new LinkedList<>();
}
mConnectionCallbacksList.add(listener);
}
#Override
public boolean isConnectionCallbacksRegistered(ConnectionCallbacks listener) {
return mConnectionCallbacksList.contains(listener);
}
#Override
public void unregisterConnectionCallbacks(ConnectionCallbacks listener) {
mConnectionCallbacksList.remove(listener);
}
#Override
public void registerConnectionFailedListener(OnConnectionFailedListener listener) {
...
}
#Override
public boolean isConnectionFailedListenerRegistered(OnConnectionFailedListener listener) {
...
}
#Override
public void unregisterConnectionFailedListener(OnConnectionFailedListener listener) {
...
}
#Override
public void disconnect() {
}
private final Runnable postLocationUpdateRunnable = new Runnable() {
#Override
public void run() {
try {
mPendingIntent.send(mContext, 1234, new Intent()); // in the intent should probably be the mocked activity data - I dont know the exact structure, it should be documented
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
mHandler.postDelayed(this, interval);
}
};
}
You can check this code, This is also include how you can get location of user when particular activity occurs.
MainActivity
class MainActivity : AppCompatActivity(), GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks {
override fun onConnected(p0: Bundle?) {
requestActivityUpdates()
}
override fun onConnectionSuspended(p0: Int) {
Log.e("location", "connection suspended, retry to connect")
apiClient.connect()
}
override fun onConnectionFailed(p0: ConnectionResult) {
Log.e("location", "connection error ${p0.errorMessage}")
}
lateinit var apiClient: GoogleApiClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
init()
}
override fun onStart() {
super.onStart()
apiClient.connect()
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.ACCESS_COARSE_LOCATION), 100)
}
}
override fun onStop() {
super.onStop()
if (apiClient.isConnected)
apiClient.disconnect()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
100 -> {
if (grantResults.isNotEmpty() && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "You must assign permission of your location", Toast.LENGTH_SHORT).show()
finish()
}
}
}
}
private fun init() {
apiClient = GoogleApiClient.Builder(this).addApi(ActivityRecognition.API).addConnectionCallbacks(this).addOnConnectionFailedListener(this).build()
}
fun requestActivityUpdates() {
if (!apiClient.isConnected) {
Toast.makeText(this, "GoogleApiClient not yet connected", Toast.LENGTH_SHORT).show()
} else {
ActivityRecognition.getClient(this).requestActivityUpdates(0, getActivityDetectionPendingIntent())
}
}
fun removeActivityUpdates() {
ActivityRecognition.getClient(this).removeActivityUpdates(getActivityDetectionPendingIntent())
}
private fun getActivityDetectionPendingIntent(): PendingIntent {
val intent = Intent(this, ActivityRecognizeService::class.java)
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
}
Service
class ActivityRecognizeService : IntentService("LjRecognize") {
lateinit var location: Location
private var fusedLocationClient: FusedLocationProviderClient? = null
override fun onHandleIntent(intent: Intent?) {
if (intent == null)
return
if (ActivityRecognitionResult.hasResult(intent)) {
val result = ActivityRecognitionResult.extractResult(intent)
val time = System.currentTimeMillis()
result.probableActivities.forEach {
when (it.type) {
DetectedActivity.IN_VEHICLE -> {
Log.e("Activity found", "on vehicle at " + time + " with confidence of " + it.confidence)
}
DetectedActivity.ON_BICYCLE -> {
Log.e("Activity found", "on bicycle at " + time + " with confidence of " + it.confidence)
}
DetectedActivity.ON_FOOT -> {
Log.e("Activity found", "on foot at " + time + " with confidence of " + it.confidence)
getLocation()
}
DetectedActivity.STILL -> {
Log.e("Activity found", "still at " + time + " with confidence of " + it.confidence)
}
DetectedActivity.UNKNOWN -> {
Log.e("Activity found", "unknown at " + time + " with confidence of " + it.confidence)
}
DetectedActivity.TILTING -> {
Log.e("Activity found", "tilted at " + time + " with confidence of " + it.confidence)
}
}
}
}
}
private fun getLocation() {
if (fusedLocationClient == null)
fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
fusedLocationClient!!.lastLocation.addOnSuccessListener {
if (it != null)
location = it
Log.e("location", "found -> lat: ${location.latitude}, lng: ${it.longitude}")
}
} else {
startActivity(Intent(this, MainActivity::class.java))
}
}
}
Don't forgot to add permissions
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Android: Trying to move a location finder and volley request into a service

I'm a bit new to Android and I'm trying to move some location finding and volley methods out of my fragment into a service, but now sure where to put what. It's basically a weather app that gets your current location and uses volley to pull forecast.io api data.
Here is my fragment now:
public class WeatherListFragment extends ListFragment implements LocationListener {
private final String initialURL = "https://api.forecast.io/forecast/8fc2b0556e166fa4670d4014d318152a/";
Weather[] myWeatherArray = {};
Weather myWeatherObject;
WeatherAdapter weatherAdapter;
LocationManager mLocationManager;
String currentLoc;
JSONArray data;
JSONObject day;
#Override
public void onLocationChanged(Location location) {
// Called when a new location is found by the network location provider.
makeUseOfNewLocation(location);
// Remove the listener you previously added
mLocationManager.removeUpdates(this);
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mLocationManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
makeUseOfNewLocation(mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER));
mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1, 1, this);
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1, 1, this);
}
public void getData() {
String API_URL = setLatLong(initialURL, currentLoc);
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, API_URL, null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
try {
JSONObject daily = response.getJSONObject("daily");
data = daily.getJSONArray("data");
myWeatherArray = new Weather[data.length()];
for (int i = 0; i < myWeatherArray.length; i++) {
day = data.getJSONObject(i);
myWeatherObject = new Weather();
myWeatherObject.setmDate(day.getInt("time"));
myWeatherObject.setmTempMin(day.getInt("temperatureMin"));
myWeatherObject.setmTempMax(day.getInt("temperatureMax"));
myWeatherObject.setIcon(day.getString("icon"));
myWeatherArray[i] = myWeatherObject;
}
} catch (JSONException e) {
e.printStackTrace();
}
if (weatherAdapter != null) {
weatherAdapter.setData(myWeatherArray);
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getActivity(), "volley died", Toast.LENGTH_SHORT).show();
}
}
);
requestQueue.add(jsonObjectRequest);
}
public void makeUseOfNewLocation(Location location) {
if (location == null) {
return;
}
mLocationManager.removeUpdates(this);
double latDouble = location.getLatitude();
double longDouble = location.getLongitude();
String latString = String.valueOf(latDouble);
String longString = String.valueOf(longDouble);
String latLong = latString + "," + longString;
Log.e("gps", latLong);
currentLoc = latLong;
getData();
}
public String setLatLong(String roughURL, String loc) {
return roughURL + loc;
}
and here is the blank Service class using a Handler:
public class NotificationService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
Notification n = new Notification(getApplicationContext());
// Stop the service using the startId, so that we don't stop
// the service in the middle of handling another job
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block. We also make it
// background priority so CPU-intensive work will not disrupt our UI.
HandlerThread thread = new HandlerThread("ServiceStartArguments",
Thread.MIN_PRIORITY);
thread.start();
// Get the HandlerThread's Looper and use it for our Handler
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();
// For each start request, send a message to start a job and deliver the
// start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
// If we get killed, after returning from here, restart
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// We don't provide binding, so return null
return null;
}
#Override
public void onDestroy() {
Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
}
}

Categories

Resources