I am trying to get HARDWARE_HOOK button and volume change button in my service using MediaSession for Android 5.0+ . This has to work specially when screen is off/locked.
The problem is that though I am able to receive HARDWARE_HOOK button event, the volume change is not detected. the onAdjustVolume method never gets called.
import android.app.Service;
import android.content.Intent;
import android.media.MediaRouter;
import android.media.session.MediaSession;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.media.VolumeProviderCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.Toast;
public class HookButtonService extends Service{
public static final String SESSION_TAG = "SampleApp";
private MediaSessionCompat mMediaSession;
private VolumeProviderCompat myVolumeProvider;
public class ServiceBinder extends Binder {
public HookButtonService getService() {
return HookButtonService.this;
}
}
private Binder mBinder = new ServiceBinder();
private MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() {
#Override
public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
Log.d("SampleApp","Media button received");
if(!MyApplication.isActivityVisible()) {
Intent dialogIntent = new Intent(getApplicationContext(), MainActivity.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
}
return true;
}
};
public HookButtonService() {
}
public MediaSessionCompat.Token getMediaSessionToken() {
return mMediaSession.getSessionToken();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onCreate() {
super.onCreate();
mMediaSession = new MediaSessionCompat(this, SESSION_TAG);
mMediaSession.setCallback(mMediaSessionCallback);
myVolumeProvider = new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, 100, 50) {
#Override
public void onAdjustVolume(int direction) {
Log.d("SampleApp","Volume change received: "+direction);
}
};
mMediaSession.setActive(true);
mMediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
mMediaSession.setPlaybackToRemote(myVolumeProvider);
}
#Override
public void onDestroy() {
super.onDestroy();
mMediaSession.release();
}
}
onAdjustVolume and VolumeProviderCompat are desired to work with remote displays, when you play some music/video using casting. method won't fire when you are using on-device buttons during e.g. silence and screen-off. confusing class name, its not so universal as it sounds...
afaik at the beginning of 2021 there is no reliable way for intercepting volume button presses when screen off, probably even detecting... (#op if you found solution please post)
The reason is probably that this is one of intended "features" of Android for reducing battery draining during screen off - distributing button presses straight to lower audio-managing layers ommiting framework/apps, not allowing to execute some additional code (which we want to do)
Related
I am trying to create a simple App Lock for Android App. So I created app lock service like this
package com.company.applock;
import android.app.ActivityManager;
import android.app.Service;
import android.content.Intent;
import android.content.Context;
import android.os.IBinder;
import android.util.Log;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import com.company.applock.LockscreenActivity;
public class LockService extends Service {
private static boolean isLock = false;
private Timer timer;
// Static Getters and setters
public static boolean isLock() {
return isLock;
}
public static void setLock(boolean lock) {
isLock = lock;
}
// Public static method to start service
public static void start(Context context) {
Intent intent = new Intent(context, LockService.class);
context.startService(intent);
}
// Overrides
#Override
public IBinder onBind(Intent intent) { return null; }
#Override
public void onCreate() {
timer = new Timer("LockService");
timer.schedule(checkLockTask, 500L, 500L);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (null != intent) { }
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel(); timer = null;
}
// Custom methods
private boolean isForegroundLocked() {
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> taskInfo = am.getRunningTasks(1);
Log.d("topActivity", taskInfo.get(0).topActivity.getClassName());
return taskInfo.get(0).topActivity.getClassName().equals("com.company.applock.LockscreenActivity");
}
private void showLockActivity() {
Intent intent = new Intent(getApplicationContext(), LockscreenActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Log.d("showLockActivity", "success");
}
private TimerTask checkLockTask = new TimerTask() {
#Override
public void run() {
// TODO: Fix foreground bug
if (isLock) {
Log.d("isLock", "true");
if (isForegroundLocked()) {
Log.d("isForegroundLocked", "true");
} else {
Log.d("isForegroundLocked", "false");
showLockActivity();
}
} else {
Log.d("isLock", "false");
// TODO: Close lock screen
}
}
};
}
As you see, this is very simple one. The problem is;
When I press home button and get to launcher, it locks after a few seconds (generally 4 or 5 seconds)
If I remove my main activity (this is not lockscreen activity) from recent tasks, the service stops (it doesn't stop when I press home button).
So, anyone who knows the solution for these problem, please help me. I am new to Android.
Thank you.
I am studying services, and I have written a code to bind a service by clicking on a button, run a method of the service by clicking on another button and unbinding service by clicking on a third button.
If I try to run the method of the service before binding. I get, obviously, an error message, while if I first bind the service the method is normally called.
The question is, If I click on the third button to unbind the service, despite the service native method on Unbind(Intent intent) gives me a positive feedback, I'm still able to call the service method from the main activity like if it should still be bound.
Here is the Service code
package com.antonello.tavolaccio4;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
/**
* Created by Antonello on 14/05/2017.
*/
public class Servizio extends Service{
public IBinder binder=new MyBinder();
#Nullable
#Override
public IBinder onBind(Intent intent) {
return binder;
}
#Override
public boolean onUnbind(Intent intent){
System.out.println("unbinded");
return false;
}
public class MyBinder extends Binder{
Servizio getService(){
return Servizio.this;
}
}
public void metodo(){
System.out.println("Metodo del service");
}
}
and here is the Main Activity code:
package com.antonello.tavolaccio4;
import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
ServiceConnection serviceConnection;
Servizio servizio;
Button button;
Button button2;
Button button3;
boolean bound;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button)findViewById(R.id.button);
button2=(Button)findViewById(R.id.button2);
button3=(Button)findViewById(R.id.button3);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),Servizio.class);
bindService(intent,serviceConnection, Service.BIND_AUTO_CREATE);
}
});
button2.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
servizio.metodo();
}
});
button3.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
Intent intent=new Intent(getApplicationContext(),Servizio.class);
unbindService(serviceConnection);
}
});
serviceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
Servizio.MyBinder binder=(Servizio.MyBinder)service;
servizio=binder.getService();
bound=true;
System.out.println(bound);
}
#Override
public void onServiceDisconnected(ComponentName name) {
}
};
}
}
Is there anything wrong in my unbindService method?
Thank you for any help.
Is there anything wrong in my unbindService method?
You do not have an unbindService() method. You are calling the one that you are inheriting from Context.
It is your job, as part of calling unbindService(), to also set to null any fields tied to the bound connection (in your case, servizio). As it stands, you are leaking memory, and any inherited methods that your service tries calling may throw exceptions because the service is destroyed.
I know this sounds weird, but I created a simple timer with an activity and a service (started and bound).
In the activity I also implemented onStart and onStop just logging a message (Log.d(TAG,"activity started/stopped").
The fact is that if the phone is connected to the pc everything seems to work. I can start the timer, pause it, modify and restart it. Open other apps and it keeps working on the background. I can recall it and I see the actual countdown going down. If it finish I can recall the activity from a notification and stop the ringing. etc etc
If the phone it's detached from the pc, that it works like there is no service at all. So the activity runs and if I press the home button it goes on the background and keeps working for a couple of minutes than it stops.
I can see the process in the running applications and if I recall the activity it restart from the point where it paused. That is, I set 10 minutes, I click start and then the home button. After 2-3 minutes it stops working and if I recall the activity it continues counting down from 8-7 minutes...
Any idea?
The activity:
package com.sleone.cookingtimer;
import com.sleone.cookingtimer.TimerService.LocalBinder;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import kankan.wheel.widget.WheelView;
import kankan.wheel.widget.adapters.NumericWheelAdapter;
import android.util.Log;
public class TimerMainActivity extends Activity {
// private CookingTimer timer;
// suppressWarnings because is initialized binding to the service
private TimerService timerService;
private Intent timerServiceIntent;
private final String TAG = "TimerMainActivity";
private WheelView hoursWheel ;
private WheelView minutesWheel;
private WheelView secondsWheel;
/*
* Initialize the activity
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_timer_main);
timerServiceIntent = new Intent(this, TimerService.class);
startTimerService();
// init the gui
hoursWheel = (WheelView) findViewById(R.id.hoursWheelView);
minutesWheel = (WheelView) findViewById(R.id.minutesWheelView);
secondsWheel = (WheelView) findViewById(R.id.secondsWheelView);
hoursWheel.setViewAdapter(new NumericWheelAdapter(this, 0, 6));
minutesWheel.setViewAdapter(new NumericWheelAdapter(this, 0, 59));
secondsWheel.setViewAdapter(new NumericWheelAdapter(this, 0, 59));
}
#Override
protected void onStop(){
super.onStop();
Log.d(TAG, "TimerMainActivity stopped");
}
#Override
protected void onStart(){
super.onStart();
Log.d(TAG, "TimerMainActivity started");
}
private void startTimerService() {
// connect to the service
// leave the service in background
Log.d(TAG, "Starting the TimerService");
startService(timerServiceIntent);
// interact with the service
Log.d(TAG, "Binding to the TimerService");
bindService(timerServiceIntent, mConnection, Context.BIND_AUTO_CREATE);
}
private void stopTimerService() {
unbindService(mConnection);
stopService(timerServiceIntent);
}
/*
* Disconnect from the service
*/
#Override
protected void onDestroy() {
Log.d(TAG, "Stopping TimerService");
super.onStop();
stopTimerService();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.timer_main, menu);
return true;
}
public void controlTimer(View view) {
Button controlButton = (Button) findViewById(R.id.controlTimerButton);
if (controlButton.getText().equals(
getResources().getText(R.string.startTimer))) {
if ((hoursWheel.getCurrentItem() == 0)
&& (minutesWheel.getCurrentItem() == 0)
&& (secondsWheel.getCurrentItem() == 0)) {
return;
}
controlButton.setText(R.string.stopTimer);
timerService.startTimer();
} else {
controlButton.setText(R.string.startTimer);
timerService.stopTimer();
}
}
/* Defines callbacks for service binding, passed to bindService() */
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder service) {
// We've bound to LocalService, cast the IBinder and get
// LocalService instance
LocalBinder binder = (LocalBinder) service;
timerService = binder.getService();
binder.createCookingTimer(TimerMainActivity.this);
Log.d(TAG, "onServiceConnected() finished");
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
Log.e(TAG, "TimerService unexpectedly disconnected!!");
}
};
}
The service:
package com.sleone.cookingtimer;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
public class TimerService extends Service{
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
private CookingTimer timer;
//private int timerServiceId;
public class LocalBinder extends Binder {
public TimerService getService() {
// Return this instance of LocalService so clients can call public methods
return TimerService.this;
}
// when the client connects to the service instantiate the CookingImer
public void createCookingTimer(TimerMainActivity timerMainActivity){
timer = new CookingTimer(timerMainActivity);
}
}
public void startTimer(){
timer.startTimer();
}
public void stopTimer(){
timer.stopTimer();
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return mBinder;
}
}
I don't think you need the timer itself. It;s just a CountDownTimer which onTick it updates the hours/minutes/seconds Wheel and onFinish plays a sound and create a notification.
You might have some sort of race condition, that when connected to the PC, execution is a bit slower, but when not connected the timing is a bit different and the order of execution changes. It's hard to tell without the code.
Ok, I guess I figured it out.
Basically I did not understand exactly that a service could also be paused when the cpu goes to sleep.
So, my guess is that while on the emulator or with the cable connected the cpu never goes to sleep because there is no battery consumption.
To wake up the application even from the cpu sleep I used an AlarmManger with the AlarmManager.RTC_WAKEUP flag.
I'm trying to create a service which will start by the user request in the application.
After the user will choose an update interval, the service will run in the operation system background, and will send a non-relevant message.
I've tried to write the service according to the example for Service class API.
For some reason, I figured in debug (when running doBindService() method) that mUpdateBoundService is getting null.
My second question is whether I can use "Toast" inform message outside an application ? (As kind of a desktop notification).
Can anyone help ? Here is my short code:
UpdateService.java
package android.update;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;
public class UpdateService extends Service {
private NotificationManager mNM;
private final IBinder mBinder = new UpdateBinder();
private int updateInterval;
public class UpdateBinder extends Binder {
UpdateService getService() {
return UpdateService.this;
}
}
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Timer timer = new Timer();
timer.schedule(new UpdateTimeTask(), 100, updateInterval);
}
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
class UpdateTimeTask extends TimerTask {
public void run() {
showNotification();
}
}
public void showNotification() {
Toast.makeText(this, "Hi", 10);
}
#Override
public IBinder onBind(Intent intent) {
updateInterval = intent.getExtras().getInt(getString(R.string.keyUpdateInterval));
return mBinder;
}
}
UpdateActivity.java
package android.update;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class UpdateActivity extends Activity {
private UpdateService mUpdateBoundService;
private boolean mIsBound = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onClickStartUpdateService(View view) {
switch (view.getId()) {
case R.id.btnStartUpdateService:
doBindService();
//Toast.makeText(this,"Service Started",Toast.LENGTH_LONG).show();
mUpdateBoundService.showNotification();
break;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mUpdateBoundService = ((UpdateService.UpdateBinder)service).getService();
}
public void onServiceDisconnected(ComponentName className) {
mUpdateBoundService = null;
}
};
private void doBindService() {
Intent updateActivityIntent = new Intent(UpdateActivity.this,
UpdateService.class);
EditText txtUpdateInterval = (EditText) findViewById(R.id.txtUpdateInterval);
int interval = Integer.parseInt(txtUpdateInterval.getText().toString());
updateActivityIntent.putExtra(getString(R.string.keyUpdateInterval), interval);
bindService(updateActivityIntent, mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
}
Your toast is not showing because you are not telling it to. Try:
public void showNotification() {
Toast.makeText(this, "Hi", 10).show();
}
For your service issue, I think that you do not properly understand how services & activities work together. A service can run independently of a service, or you can have a service whose lifecycle matches that of a given activity. From your code, it is not clear which of these models you are following. Your implementation will cause the service to wake periodically, but only while your activity is running. If the user switches to another activity, your service will no longer be woken.
If you want a service to wake periodically independently of the activity, then you need to run your timer event in the service itself. Better still use an Alarm to wake your service: Register an Alarm with AlarmManager which will fire an Intent at a future point (or regular intervals, if you prefer), and extend your service from IntentService, override onHandleIntent() and add the necessary Intent Filter to your Service entry in the manifest.
I finally got the Local Service Sample to work using the LocalServiceActivities.java and the Basics of Android : Part III – Android Services.
Here's my code Controller.java, LocalService.java, Binding.java, and ILocalService.java all baked together one after another separated by comment headers:
/**************************************************************************************************
* Filename: Controller.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the primary activity for this application
**************************************************************************************************/
package com.marie.localservicesample;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/*
* Example of explicitly starting and stopping the local service.
* This demonstrates the implementation of a service that runs in the same
* process as the rest of the application, which is explicitly started and stopped
* as desired.
*/
//public static class Controller extends Activity {
public class Controller extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.local_service_controller);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.start);
button.setOnClickListener(mStartListener);
button = (Button)findViewById(R.id.stop);
button.setOnClickListener(mStopListener);
}
private OnClickListener mStartListener = new OnClickListener() {
public void onClick(View v) {
// Make sure the service is started. It will continue running
// until someone calls stopService(). The Intent we use to find
// the service explicitly specifies our service component, because
// we want it running in our own process and don't want other
// applications to replace it.
//startService(new Intent(Controller.this, LocalService.class));
Intent startSvc = new Intent(Controller.this, LocalService.class);
startSvc.putExtra(LocalService.EXTRA_MESSENGER, new Messenger(handler));
startSvc.putExtra(LocalService.EXTRA_SONG, 7);
startService(startSvc);
Intent binding = new Intent(Controller.this, Binding.class);
startActivity(binding);
}
};
private OnClickListener mStopListener = new OnClickListener() {
public void onClick(View v) {
// Cancel a previous call to startService(). Note that the
// service will not actually stop at this point if there are
// still bound clients.
stopService(new Intent(Controller.this,
LocalService.class));
}
};
/*
* This is a handler to be passed to the Service via a Messenger.
*/
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
// simple handler test
String obj = (String) msg.obj;
Log.i("handleMessge", "obj: " + obj);
}
};
}
/**************************************************************************************************
* Filename: LocalService.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains a local service
**************************************************************************************************/
package com.marie.localservicesample;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
public class LocalService extends Service {
private NotificationManager mNM;
// Unique Identification Number for the Notification.
// We use it on Notification start, and to cancel it.
//private int NOTIFICATION = R.string.local_service_started;
private int NOTIFICATION = R.string.local_service_started;
private int statusCode = 10;
// This is the object that receives interactions from clients. See
// RemoteService for a more complete example.
private final IBinder mBinder = new LocalBinder();
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* Class for clients to access. Because we know this service always
* runs in the same process as its clients, we don't need to deal with
* IPC.
*/
public class LocalBinder extends Binder implements ILocalService {
LocalService getService() {
return LocalService.this;
}
#Override
public int getStatusCode() {
return statusCode;
}
}
public static final String EXTRA_MESSENGER = "com.marie.localservicesample.EXTRA_MESSENGER";
private Messenger messenger;
public static final String EXTRA_SONG = "com.marie.localservicesample.EXTRA_SONG";
private int song;
#Override
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// Display a notification about us starting. We put an icon in the status bar.
showNotification();
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
}
/*
* This is the ServiceWorker thread that passes messages to the handler defined in
* the MainActivity class.
* NOTE: Instead of passing messages to a handler in MainActivity I would like
* it to pass messages to a handler defined in the RcvMessages activity.
*/
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here... something simple
while (messenger == null);
// send a message to the handler
try {
Message msg = Message.obtain();
msg.obj = "Hello " + "Song " + song;
msg.arg1 = song;
messenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
// stop the service when done...
// LocalService.this.stopSelf();
// Or use the unbindBtn in the MainActivity class.
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("LocalService", "Received start id " + startId + ": " + intent);
Bundle extras = intent.getExtras();
messenger = (Messenger)extras.get(EXTRA_MESSENGER);
try {
song = (Integer) extras.get(EXTRA_SONG);
} catch (NullPointerException e) {
e.printStackTrace();
song = 0;
}
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onDestroy() {
// Cancel the persistent notification.
mNM.cancel(NOTIFICATION);
// Tell the user we stopped.
Toast.makeText(this, R.string.local_service_stopped, Toast.LENGTH_SHORT).show();
}
/**
* Show a notification while this service is running.
*/
private void showNotification() {
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.local_service_started);
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.stat_sample, text,
System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
//PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, LocalServiceActivities.Controller.class), 0);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, Controller.class), 0);
// Set the info for the views that show in the notification panel.
notification.setLatestEventInfo(this, getText(R.string.local_service_label),
text, contentIntent);
// Send the notification.
mNM.notify(NOTIFICATION, notification);
}
/* Duplicate added by Eclipse
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
*/
}
/**************************************************************************************************
* Filename: Binding.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains the binding for this application
**************************************************************************************************/
package com.marie.localservicesample;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
/*
* Example of binding and unbinding to the local service.
* This demonstrates the implementation of a service which the client will
* bind to, receiving an object through which it can communicate with the service.
*/
public class Binding extends Activity {
private boolean mIsBound;
private LocalService mBoundService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. Because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its IBinder to a concrete class and directly access it.
mBoundService = ((LocalService.LocalBinder)service).getService();
ILocalService localService = (ILocalService)service;
int statusCode = localService.getStatusCode();
Log.d("Binding","called onServiceConnected. statusCode: " + statusCode);
Toast.makeText(Binding.this, R.string.local_service_connected,
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// Because it is running in our same process, we should never
// see this happen.
mBoundService = null;
Log.d("Binding", "called onServiceDisconnected");
Toast.makeText(Binding.this, R.string.local_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};
void doBindService() {
// Establish a connection with the service. We use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindService(new Intent(Binding.this,
LocalService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
}
}
#Override
protected void onDestroy() {
super.onDestroy();
doUnbindService();
}
private OnClickListener mBindListener = new OnClickListener() {
public void onClick(View v) {
doBindService();
}
};
private OnClickListener mUnbindListener = new OnClickListener() {
public void onClick(View v) {
doUnbindService();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.local_service_binding);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.bind);
button.setOnClickListener(mBindListener);
button = (Button)findViewById(R.id.unbind);
button.setOnClickListener(mUnbindListener);
}
}
/**************************************************************************************************
* Filename: ILocalService.java
* Project name: Local Service Sample
* Application name: Local Service
* Description: This file contains an example interface for LocalService
**************************************************************************************************/
package com.marie.localservicesample;
public interface ILocalService {
// An example method for ILocalService
public int getStatusCode();
}
My question is why would anyone want to provide an ILocalService.java if they already have a startService() with a thread and a handler like I do? My ILocalService.java is a trivial demo which asks for a statusCode. As far as I can tell my ILocalService.java will only consist of getters of status and no setters. So will I only be asking for status info of my local service? What would be an example of a setter to my local service?
Your binder looks like this:
public class LocalBinder extends Binder implements ILocalService {
LocalService getService() {
return LocalService.this;
}
#Override
public int getStatusCode() {
return statusCode;
}
}
The key part of interest is getService. What this means is that any of your Activities that bind to your Service (since this is a local service) can actually obtain the service object and can call ANY functions on that service function, not just getters. You aren't limited to just the narrow communication channel that is startService and the Intent, you have the full method interface for the service object. In the past I've passed BluetoothDevice instances, Handler instances and other complex Java objects through to the service object.