I have an Android project in which I use a service in order, I'm currently using this service to watch the MediaPlayer and events go through the BR.
package com.uk.jacob.groovebuddy;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
public class MediaSyncService extends Service {
#Override
public void onCreate() {
super.onCreate();
IntentFilter iF = new IntentFilter();
iF.addAction("com.android.music.metachanged");
iF.addAction("com.htc.music.metachanged");
iF.addAction("fm.last.android.metachanged");
iF.addAction("com.sec.android.app.music.metachanged");
iF.addAction("com.nullsoft.winamp.metachanged");
iF.addAction("com.amazon.mp3.metachanged");
iF.addAction("com.miui.player.metachanged");
iF.addAction("com.real.IMP.metachanged");
iF.addAction("com.sonyericsson.music.metachanged");
iF.addAction("com.rdio.android.metachanged");
iF.addAction("com.samsung.sec.android.MusicPlayer.metachanged");
iF.addAction("com.andrew.apollo.metachanged");
registerReceiver(mReceiver, iF);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction() != null) {
String track = intent.getStringExtra("track");
String album = intent.getStringExtra("album");
String artist = intent.getStringExtra("artist");
Log.d("Test", "Your listening to " + track + " on the album " + album + " by the artist " + artist);
}
}
};
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed...", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
The broadcast receiver is being triggered twice and as such I see the output
Your listening to After Midnight on the album Neighborhoods (Deluxe Explicit Version) by the artist blink-182
Your listening to After Midnight on the album Neighborhoods (Deluxe Explicit Version) by the artist blink-182
As you can see I am registering the BR only once.
Related
i want to make an application that i can run it over voice like siri or google assistant, so in order to make it i have to implement the code in a background or foreground service which will run speech recognizer
so is this possible,because of the limitation of the working services on android Oreo and higher this make me stuck in the middle of nowhere
and i'm not so professional so i could figure this out myself
i have tried to make a foreground service with IntentService so that it could make the work on the background without freezing the UI
and the Speech recognizer didn't work
package com.example.intentservice;
import android.app.IntentService;
import android.app.Notification;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
import android.speech.RecognitionListener;
import android.speech.RecognizerIntent;
import android.speech.SpeechRecognizer;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import java.util.List;
import java.util.Locale;
import static com.example.intentservice.App.CHANNEL_ID;
public class ExampleService extends IntentService {
public static final String TAG = "ExampleService";
private PowerManager.WakeLock wakeLock;
private TextToSpeech textToSpeech;
private SpeechRecognizer recognizer;
#Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate");
initRec();
startListening();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ExampleService:wakelock");
wakeLock.acquire();
Log.e(TAG, "wakelock acquired");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification notification = new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("noti")
.setContentText("running")
.build();
startForeground(1, notification);
}
}
private void startListening() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS,1);
recognizer.startListening(intent);
}
private void initRec() {
if (SpeechRecognizer.isRecognitionAvailable(this)) {
recognizer = SpeechRecognizer.createSpeechRecognizer(this);
recognizer.setRecognitionListener(new RecognitionListener() {
#Override
public void onReadyForSpeech(Bundle bundle) {
}
#Override
public void onBeginningOfSpeech() {
}
#Override
public void onRmsChanged(float v) {
}
#Override
public void onBufferReceived(byte[] bytes) {
}
#Override
public void onEndOfSpeech() {
}
#Override
public void onError(int i) {
}
#Override
public void onResults(Bundle bundle) {
List<String> res = bundle.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
Toast.makeText(ExampleService.this, res.get(0), Toast.LENGTH_SHORT).show();
}
#Override
public void onPartialResults(Bundle bundle) {
}
#Override
public void onEvent(int i, Bundle bundle) {
}
});
}
}
public ExampleService() {
super("ExampleService");
// to create service again
setIntentRedelivery(true);
}
// this just to test the code
#Override
protected void onHandleIntent(#Nullable Intent intent) {
Log.e(TAG, "onHandleIntent");
String string = intent.getStringExtra("key");
for (int i = 0; i < 10; i++) {
Log.e(TAG, string + "-" + i);
// Toast.makeText(this, "i", Toast.LENGTH_SHORT).show();
SystemClock.sleep(1000);
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy");
wakeLock.release();
Log.e(TAG, "wakelock realised");
}
}
I want to make an app that shows a notification as soon as headphone is plugged in and remove it when it is plugged out. My app works fine when it is on or home button is pressed, but doesn't work when back is pressed or app is closed by long pressing home and swiping it away. What should I use in order to make it work?
This is my code
package com.example.earphone;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
public class HeadsetPlugReceiver extends BroadcastReceiver {
TextView t1;
#Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
return;
}
boolean connectedHeadphones = (intent.getIntExtra("state", 0) == 1);
// boolean connectedMicrophone = (intent.getIntExtra("microphone", 0) == 1) && connectedHeadphones;
String headsetName = intent.getStringExtra("name");
Log.v("message", "headphone connected" + headsetName);
Intent i = new Intent(context, MainActivity.class);
PendingIntent p = PendingIntent.getActivity(context,0,i,0);
// Toast.makeText(context, "Headphone connected", Toast.LENGTH_SHORT).show();
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", -1);
if(state==1){
Intent intent1 = new Intent(context, ES.class);
context.startForegroundService(intent1);
}
switch (state) {
case 0:
Intent intent1 = new Intent(context, ES.class);
context.stopService( intent1);
Toast.makeText(context, "Headphone ejected", Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(context, "Headphone connected", Toast.LENGTH_SHORT).show();
break;
default:
Toast.makeText(context, "I have no idea what the headset state is", Toast.LENGTH_SHORT).show();
}
}
}}
package com.example.earphone;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.os.Build;
public class App extends Application {
public static final String C_ID = "noti";
#Override
public void onCreate() {
super.onCreate();
createnoti();
}
private void createnoti(){
if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.O){
NotificationChannel nc = new NotificationChannel(
C_ID,"ex", NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager nm= getSystemService(NotificationManager.class);
nm.createNotificationChannel(nc);
}
}
}
package com.example.earphone;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import static com.example.earphone.App.C_ID;
public class ES extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent ni = new Intent(this,HeadsetPlugReceiver.class);
PendingIntent pi = PendingIntent.getActivity(this,0,ni,0);
Notification notification = new NotificationCompat.Builder(this, C_ID)
.setContentTitle("Headphones plugged in")
.setContentText("currently plugged in")
.setSmallIcon(R.mipmap.ic_launcher).setContentIntent(pi).build();
startForeground(1,notification);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
public class MainActivity extends AppCompatActivity {
Button b;
HeadsetPlugReceiver headsetPlugReceiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = findViewById(R.id.b);
// Intent intent = new Intent(this, ES.class);
//startService(intent);
headsetPlugReceiver = new HeadsetPlugReceiver();
IntentFilter i = new IntentFilter();
i.addAction("android.intent.action.HEADSET_PLUG");
registerReceiver(headsetPlugReceiver,i);
}
}
I'm working on an application to communicate with a raspberry pi. The app communicates with the server via a socket connection.
I'm currently able to building up the communication and holding it in a service. But my goal is to change from activity A to activity B. The problem is, that my application destroys the service when im switching the activities. Is there a way to avoid this?
Activity A starts the service and when im starting Activity B i bind it to the activity to call the methods in the service class. But it isn't the same instance.
How could i solve this?
Code
ConnectActivity
package com.example.domen.twitchdronev3;
import android.content.Intent;
import android.os.Parcelable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class ConnectActivity extends AppCompatActivity {
private int port = 3000;
private String ip = "localhost";
private Intent serviceIntent, activityIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_connect);
Toast.makeText(getApplicationContext(), "Starte App...", Toast.LENGTH_LONG).show();
activityIntent = new Intent(this, ControllActivity.class);
serviceIntent = new Intent(this, ClientService.class);
serviceIntent.putExtra("ip", ip);
serviceIntent.putExtra("port", port);
Button btnActivity = (Button) findViewById(R.id.changeActivity);
btnActivity.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startService(serviceIntent);
activityIntent.putExtra("Intent", (Parcelable) serviceIntent);
startActivity(activityIntent);
}
});
}
// destroys the Activity
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getApplicationContext(), "Destroy (ConnectActivity)", Toast.LENGTH_LONG).show();
}
// Activity stopping
#Override
protected void onStop() {
super.onStop();
}
}
ControllActivity
package com.example.domen.twitchdronev3;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class ControllActivity extends AppCompatActivity {
public static final String TAG = "ControllActivity";
private ClientService clientservice;
private Intent serviceIntent;
private boolean isBound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_controll);
Bundle extras = getIntent().getExtras();
serviceIntent = extras.getParcelable("Intent");
Button btnDisconnect = (Button) findViewById(R.id.btnDisconnect);
btnDisconnect.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View view) {
doBindToService();
}
});
}
// destroys the Activity
#Override
public void onDestroy(){
super.onDestroy();
Toast.makeText(getApplicationContext(), "Destroy (ControllActivity)", Toast.LENGTH_LONG).show();
doUnbindToService();
stopService(serviceIntent);
}
// Functions to BIND and UNBIND the SERVICE
// bind to Service
public void doBindToService(){
if(!isBound) {
Toast.makeText(this, "(doBindToService) Binding...", Toast.LENGTH_LONG).show();
isBound = bindService(serviceIntent, myConnection, Context.BIND_AUTO_CREATE);
}
}
// Unbind to Service
public void doUnbindToService(){
Toast.makeText(this, "(doUnbindToService) Unbinding...", Toast.LENGTH_LONG).show();
unbindService(myConnection);
isBound = false;
}
private ServiceConnection myConnection = new ServiceConnection(){
public static final String TAG = "ConnectActivity";
#Override
public void onServiceConnected(ComponentName className, IBinder service){
Log.i(TAG, "BOUND SERVICE CONNECTED");
clientservice = ((ClientService.ClientBinder) service).getService();
isBound = true;
}
#Override
public void onServiceDisconnected(ComponentName name){
Log.i(TAG, "BOUND SERVICE DISCONNECTED");
clientservice = null;
isBound = false;
}
};
}
ClientService
package com.example.domen.twitchdronev3;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
/**
* Created by ViTrex on 12.02.2018.
*/
public class ClientService extends Service {
private static final String TAG = "ClientService";
private final IBinder mBinder = new ClientBinder();
private PrintWriter out;
private Socket socket;
private String ip = "";
private int port = 0;
private Thread backgroundThread;
// the class used for the client binder
public class ClientBinder extends Binder {
ClientService getService() {
// returns the instance of ClientService
// so the client can access the public methods
return ClientService.this;
}
}
//SETTER
public void setIP(String ip) {
this.ip = ip;
}
public void setPort(int port) {
this.port = port;
}
//GETTER
public String getIP() {
return this.ip;
}
public int getPort() {
return this.port;
}
#Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate...");
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_LONG).show();
if(intent != null){
setIP(intent.getStringExtra("ip"));
setPort(intent.getIntExtra("port", 3000));
}
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind called...");
Toast.makeText(this, getIP() + " " + getPort(), Toast.LENGTH_LONG).show();
backgroundThread = new Thread(new Runnable() {
#Override
public void run() {
buildConnection();
}
});
backgroundThread.start();
return mBinder;
}
private void buildConnection() {
Log.i(TAG, "Try to build up a connection ...");
synchronized (this) {
try {
this.socket = new Socket(getIP(), getPort());
this.out = new PrintWriter(this.socket.getOutputStream(), true);
Log.i(TAG, "Connected");
} catch (IOException ioe) {
Log.i(TAG, ioe.getMessage());
this.socket = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "Close Service");
Thread dummy = backgroundThread;
backgroundThread = null;
if (dummy != null)
dummy.interrupt();
if (this.socket != null) {
try {
this.out.close();
this.socket.close();
Log.i(TAG, "Close Socket");
} catch (IOException ioe) {
Log.i(TAG, "ERROR: Close Socket");
}
}
}
}
You say:
Activity A starts the service and when I'm starting Activity B I bind
it to the activity to call the methods in the service class. But it
isn't the same instance.
How do you know it is not the same instance (presumably you mean of the service instance)?
I think your code is o.k. to run on older devices (It runs o.k. on my device. pre-API26, I think permissions changed after then so maybe more code needed. See NOTE at the end of this answer).
Don't you want START_STICKY ?
I would add this code (read the Intent data that was setup by Activity A) to your ClientService.java:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
String a_ip = intent.getStringExtra("ip");
int a_port = intent.getIntExtra("port",-1);
Log.i(TAG, "onStartCommand called...with " + "ip:" + a_ip + "and port:"+ a_port);
setIP(a_ip);
setPort(a_port);
return START_NOT_STICKY;//don't you want START_STICKY ?
}
Note: If your app targets API level 26 or higher, the system imposes
restrictions on using or creating background services unless the app
itself is in the foreground. If an app needs to create a foreground
service, the app should call StartForegroundService(). That method
creates a background service, but the method signals to the system
that the service will promote itself to the foreground. Once the
service has been created, the service must call its startForeground()
method within five seconds. From here
I have created a sample foreground service to check if it's possible to fetch location from background after every 15 mins or 30 mins. With introduction to doze mode alarm manager does not work at exact time.
In foreground service I have tried using handler post delay but that also does not work as I am getting intervals of upto 3 hrs. In the below code I have used ScheduledThreadPoolExecutor and it performed even worse. I got delay of upto 12 hours. I have tested this on android 6.0 as of now.
Can anyone suggest a work around for this?
package com.hitec16.foregroundservicetest;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.location.FusedLocationProviderApi;
import com.google.android.gms.location.LocationListener;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationServices;
import java.text.DateFormat;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyService extends Service
implements LocationListener, GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {
private static final String TAG = "MyService";
private static final long INTERVAL = 1000 * 10;
private static final long FASTEST_INTERVAL = 1000 * 5;
private static final long WAIT_INTERVAL = 1000 * 30;
private ScheduledThreadPoolExecutor mExecutor;
private int mCounter = 0;
private FusedLocationProviderApi fusedLocationProviderApi = LocationServices.FusedLocationApi;
LocationRequest mLocationRequest;
GoogleApiClient mGoogleApiClient;
Location mCurrentLocation;
private String mLastUpdateTime;
public MyService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
// throw new UnsupportedOperationException("Not yet implemented");
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(final Intent intent, final int flags, final int startId) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Looper.prepare();
onStart_(intent, flags, startId);
Looper.loop();
}
});
thread.start();
// onStart_(intent,flags,startId);
return START_STICKY;
}
private void onStart_(Intent intent, int flags, int startId) {
if (intent.getAction().equals(Constants.STARTFOREGROUND_ACTION)) {
Logger.d("Received Start Foreground Intent ");
createLocationRequest();
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
connectToGoogleApi();
showNotification();
Toast.makeText(getApplicationContext(), "Service Started!", Toast.LENGTH_SHORT).show();
Logger.d("work finished");
// fetchLocationAgain();
mExecutor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(2);
mExecutor.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
try {
startLocationUpdates();
} catch (Exception e) {
Log.d(getClass().getSimpleName(), "Exception caught: " + e.getMessage());
}
Log.d("Test", "test");
}
}, 30, 60 * 15, TimeUnit.SECONDS);
}
}
private void showNotification() {
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Constants.MAIN_ACTION);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Fused Location Service")
.setTicker("ticker text")
.setContentText("My Location")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE,
notification);
}
protected void createLocationRequest() {
mLocationRequest = new LocationRequest();
mLocationRequest.setInterval(INTERVAL);
mLocationRequest.setFastestInterval(FASTEST_INTERVAL);
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
protected void stopLocationUpdates() {
LocationServices.FusedLocationApi.removeLocationUpdates(
mGoogleApiClient, MyService.this);
mCounter = 0;
Logger.d("Location update stopped .......................");
}
#Override
public void onConnected(#Nullable Bundle bundle) {
Logger.d("onConnected - isConnected ...............: " + mGoogleApiClient.isConnected());
try {
startLocationUpdates();
} catch (Exception e) {
Log.d(getClass().getSimpleName(), "Exception caught: " + e.getMessage());
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
Logger.d("Connection failed: " + connectionResult.toString());
}
#Override
public void onLocationChanged(Location location) {
if (mCounter < 3) {
Log.d(getClass().getSimpleName(), "returned....");
mCounter++;
return;
}
Logger.d("Firing onLocationChanged..............................................");
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
Logger.d("Location latitude and longitude :" + location.getLatitude() + " ," + location.getLongitude()
+ " , Accuracy : " + location.getAccuracy() + ", location provider : " + location.getProvider() + "Time : " + mLastUpdateTime);
stopLocationUpdates();
}
protected void startLocationUpdates() throws Exception {
PendingResult<Status> pendingResult = LocationServices.FusedLocationApi.requestLocationUpdates(
mGoogleApiClient, mLocationRequest, this, Looper.getMainLooper());
Logger.d("Location update started ..............: ");
}
#Override
public void onDestroy() {
disconnectFromGoogleApi();
Log.d(getClass().getSimpleName(), "on destroy called");
mExecutor.shutdown();
super.onDestroy();
}
private void connectToGoogleApi() {
Logger.d("connectToGoogleApi fired ..............");
mGoogleApiClient.connect();
}
private void disconnectFromGoogleApi() {
Logger.d("disConnectFromGoogleApi fired ..............");
mGoogleApiClient.disconnect();
}
}
My Goal is to have a service that runs in the background and sends my device's location to a remote server at a specified interval (eg. every 10 minutes). I am trying to use Little Fluffy Location Library to optimize battery life while getting the device's location. I haven't been able to successfully get the location yet. I am not sure what I am doing wrong.
I followed this service tutorial and this LFLL example. Each time I run this, to Toast in MyService.java "No location found yet" displays. Additionally, it is my understanding that LFLL will loop and get the new location via the BroadcastReceiver (am I wrong on this?). However, it never attempts to get the location again and never appears to enter MyBroadcastReceiver.java.
MainActivity.java
package com.testtracker;
import android.app.Activity;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity
{
Button startButton;
Button stopButton;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startButton = (Button)findViewById(R.id.button2);
stopButton = (Button)findViewById(R.id.button);
startButton.setEnabled(true);
stopButton.setEnabled(false);
LocationManager locationManager = (LocationManager)getSystemService(LOCATION_SERVICE);
boolean locationEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(!locationEnabled)
{
Intent intent = new Intent(Settings.ACTION_LOCALE_SETTINGS);
startActivity(intent);
}
}
public void startService(View view)
{
startButton.setEnabled(false);
stopButton.setEnabled(true);
Intent intent = new Intent(getBaseContext(), MyService.class);
startService(intent);
}
public void stopService(View view)
{
startButton.setEnabled(true);
stopButton.setEnabled(false);
Intent intent = new Intent(getBaseContext(), MyService.class);
stopService(intent);
}
#Override
public boolean onCreateOptionsMenu(Menu menu)
{
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
MyService.java
package com.testtracker;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;
import android.widget.Toast;
import com.littlefluffytoys.littlefluffylocationlibrary.LocationInfo;
import com.littlefluffytoys.littlefluffylocationlibrary.LocationLibraryConstants;
public class MyService extends Service
{
protected PowerManager.WakeLock wakeLock;
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startID)
{
Log.d("LOGGER", "in start");
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
refreshDisplay();
return START_STICKY;
}
private void refreshDisplay()
{
Log.d("LOGGER", "MyService refreshDisplay()");
refreshDisplay(new LocationInfo(this));
}
private void refreshDisplay(final LocationInfo locationInfo)
{
if(locationInfo.anyLocationDataReceived())
{
Toast.makeText(this, "lat: " + Float.toString(locationInfo.lastLat) + " lng: " + Float.toString(locationInfo.lastLong) + " acc: " + Integer.toString(locationInfo.lastAccuracy) + " prov: " + locationInfo.lastProvider, Toast.LENGTH_SHORT).show();
if(locationInfo.hasLatestDataBeenBroadcast())
{
Toast.makeText(this, "Location has been broadcast", Toast.LENGTH_SHORT).show();
}
else
{
Toast.makeText(this, "Locaiton broadcast pending", Toast.LENGTH_SHORT).show();
}
}
else
{
Toast.makeText(this, "No location found yet", Toast.LENGTH_SHORT).show();
}
}
private final BroadcastReceiver lftBroadcastReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
final LocationInfo locationInfo = (LocationInfo)intent.getSerializableExtra(LocationLibraryConstants.LOCATION_BROADCAST_EXTRA_LOCATIONINFO);
refreshDisplay(locationInfo);
}
};
#Override
public void onDestroy()
{
super.onDestroy();
wakeLock.release();
Log.d("LOGGER", "MyService onDestroy");
}
}
MyApplication.java
package com.testtracker;
import android.app.Application;
import android.util.Log;
import android.widget.Toast;
import com.littlefluffytoys.littlefluffylocationlibrary.LocationLibrary;
public class MyApplication extends Application
{
#Override
public void onCreate()
{
super.onCreate();
Log.d("LOGGER", "application oncreate");
Toast.makeText(this, "in application", Toast.LENGTH_SHORT).show();
LocationLibrary.showDebugOutput(true);
try
{
LocationLibrary.initialiseLibrary(getBaseContext(), 60 * 1000, 2 * 60 * 1000, "com.testtracker");
}
catch(UnsupportedOperationException e)
{
Log.d("LOGGER", "UnsupportedOperationException thrown - the device doesn't have any location providers");
}
}
}
MyBroadcastReceiver.java
package com.testtracker;
import com.littlefluffytoys.littlefluffylocationlibrary.LocationInfo;
import com.littlefluffytoys.littlefluffylocationlibrary.LocationLibraryConstants;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "IN broadcaster!", Toast.LENGTH_SHORT).show();
Log.d("LOGGER", "BroadcastReceiver - onReceive: received location updated");
final LocationInfo locationInfo = (LocationInfo) intent.getSerializableExtra(LocationLibraryConstants.LOCATION_BROADCAST_EXTRA_LOCATIONINFO);
Intent contentIntent = new Intent(context, MainActivity.class);
PendingIntent contentPendingIntent = PendingIntent.getActivity(context, 0, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
}
I don't know you already found the issue. I feel the issue is in your Manifest file.
<service android:name="com.littlefluffytoys.littlefluffylocationlibrary.LocationBroadcastService" />
<receiver android:name="com.littlefluffytoys.littlefluffylocationlibrary.PassiveLocationChangedReceiver" android:exported="true" />
Then your receiver should have this,
<receiver android:name="com.testtracker.MyBroadcastReceiver">
<intent-filter>
<action android:name="com.testtracker.littlefluffylocationlibrary.LOCATION_CHANGED" />
</intent-filter>
</receiver>
Also, in the receiver you are getting the LocationInfo object, I feel the better approach is start your service from receiver, and pass the LocationInfo as extras to the intent.
Intent service = new Intent(context, MyService.class);
service.putExtra(LocationLibraryConstants.LOCATION_BROADCAST_EXTRA_LOCATIONINFO, locationInfo);
Then from the LocationInfo, get the latitude and longitude from your service.
final LocationInfo locationInfo = (LocationInfo) intent.getSerializableExtra(LocationLibraryConstants.LOCATION_BROADCAST_EXTRA_LOCATIONINFO);
if (locationInfo != null) {
float lat = locationInfo.lastLat;
float lng = locationInfo.lastLong;
}
Hope somebody uses this library can get help from this.