i tired this a few months ago but failed.
what i'm trying to do is count the number of times the user unlocks his phone and show it on the screen but i'm getting vague numbers each time i unlock the phone.
my code is a follows.
My main activity oncreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(getApplicationContext(), LockService.class));
TextView ticker;
ticker = (TextView) findViewById(R.id.textView);
ticker.setText(String.valueOf(Tick.tick));
Log.e("but this is awesome ", String.valueOf(Tick.tick));
}
The Service class
public class LockService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
final BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
return super.onStartCommand(intent, flags, startId);
}
public class LocalBinder extends Binder {
LockService getService() {
return LockService.this;
}
}
}
The BroadcastReceiver Class
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(final Context context, final Intent intent) {
Log.e("test", "onReceive");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
wasScreenOn = false;
Log.e("test", "wasScreenOn" + wasScreenOn);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
wasScreenOn = true;
Log.e("test", "wasScreenOn and user present" + wasScreenOn);
} else if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
Tick.tick ++;
Log.e("test", "userpresent" + Tick.tick);
}
}
}
please help me understand what i'm doing wrong
I believe what's happening is this:
each time you open your activity, you call start service. So even if your service is already running, onStartCommand is being called. This way, you register your broadcast multiple times, and then when you unlock your device your counters are being incremented for each time you reciver has been registered.
You should do one of these options:
1. Define your recievers in your manifest so you won't have to deal with registration and unregisteration each time.
2. Register you recievers in your service onCreate instead onStartCommand. Also, make sure you unregister them in your service onDestroy.
Related
I have created background service to connect my socket server, it works background while app is off, when user open the app MainActivity join to my service class and it looks fine, my service can change fragment in main activity, but when it get disconnected and want to change fragment in main activity then app crash
check my MainActivity
public class MainActivity extends AppCompatActivity {
private clientService mclientService;
private Intent mServiceIntent;
private final FragmentManager fm = getFragmentManager();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mclientService = new clientService(this);
mServiceIntent = new Intent(this, mclientService.getClass());
if (!isMyServiceRunning(mclientService.getClass())) {
startService(mServiceIntent);
}
}
public Fragment changeFragment (Fragment cls) {
FragmentTransaction ft = this.fm.beginTransaction();
ft.replace(R.id.bodyFrame, cls);
ft.commit();
return cls;
}
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("isMyServiceRunning?", true+"");
return true;
}
}
Log.i ("isMyServiceRunning?", false+"");
return false;
}
}
and the clientService:
public class clientService extends Service {
private Socket mSocket;
{
try {
IO.Options opts = new IO.Options();
opts.query = "_d=jakistakiid";
mSocket = IO.socket("http://10.0.2.2:3000", opts);
} catch (URISyntaxException e) {}
}
public clientService(MainActivity main) {
super();
mainAttach(main);
}
public clientService() {
}
public MainActivity mMain;
public void startIt(){
Log.i("eroapp", "Service Started");
if(mSocket != null) {
mSocket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("eroapp", "connected");
}
}).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
#Override
public void call(Object... args) {
Log.i("eroapp", "dc:"+mMain);
onDC();
}
});
mSocket.connect();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startIt();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Intent broadcastIntent = new Intent(this, restartReceiver.class);
sendBroadcast(broadcastIntent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
// CLIENT FUNCTIONS //
private void onDC(){
Log.i("eroapp", "DC:"+mMain);
}
private void mainAttach(MainActivity m) {
mMain = m;
Log.i("eroapp","Main created!");
if(!mSocket.connected()) {
mMain.changeFragment(new offlineFragment());
}else{
mMain.changeFragment(new singFragment());
}
}
}
looks fine, when i close app activity my service restarts and run in background, it says in logcat:
2019-11-17 02:41:22.686 17458-17458/com.example.secmsg I/eroapp: Service Started
2019-11-17 02:41:22.803 17458-17483/com.example.secmsg I/eroapp: connected
when i open app again, my service is already running, so its run only function mainAttach in clientService, and then service run changeFragment function in main activity, works great, but
when I get disconnected from server it says mMain is null ; < and logcat output:
2019-11-17 02:41:31.654 17458-17499/com.example.secmsg I/eroapp: dc:null
2019-11-17 02:41:31.654 17458-17499/com.example.secmsg I/eroapp: DCnull
The mclientService you created on the MainActivity is not the same as the clientService that was started by the Android system when you called startService(intent). All services created and started by the Android system by using the service class' empty constructor, therefore, clientService#mainAttach will never be called. Take a look at this answer for more information.
If you want to directly interact with the service on the MainActivity, you might want to bind the service to your activity. Check out the documentation about bound services here.
Another thing... It looks like you're planning to directly control the MainActivity from the service using the reference to the activity. Please never do that and use broadcasts instead. Good luck!
i try almost code in the internet, but i can't solve it.
i want to send data from specific method in the service to activity.
i use intent(putExtra), but it doesn't go to activity class.
here is my RecoBackgroundRangingService.java
(i omit unnecessary code)
private static final String TAG = "RecoBackgroundRangingService";
public static final String BROADCAST_ACTION = "com.example.hello ";
private final Handler handler = new Handler();
Intent intent;
int counter = 0;
#Override
public void onCreate() {
Log.i("BackRangingService", "onCreate()");
super.onCreate();
intent = new Intent(BROADCAST_ACTION);
Toast.makeText(getBaseContext(),"on create", Toast.LENGTH_SHORT).show();
}
#Override
public void didEnterRegion(RECOBeaconRegion region, Collection<RECOBeacon> beacons) {
/**
* For the first run, this callback method will not be called.
* Please check the state of the region using didDetermineStateForRegion() callback method.
*
//Get the region and found beacon list in the entered region
Log.i("BackRangingService", "didEnterRegion() - " + region.getUniqueIdentifier());
this.popupNotification("Inside of " + region.getUniqueIdentifier());
//Write the code when the device is enter the region
DisplayLoggingInfo();
Toast.makeText(getBaseContext(),"did enter region", Toast.LENGTH_SHORT).show();
//this.startRangingWithRegion(region); //start ranging to get beacons inside of the region
//from now, stop ranging after 10 seconds if the device is not exited
}
private void DisplayLoggingInfo() {
//Log.d(TAG, "entered DisplayLoggingInfo");
//intent.putExtra("time", new Date().toLocaleString());
//intent.putExtra("counter", String.valueOf(++counter));
intent.putExtra("status", 1);
sendBroadcast(intent);
Toast.makeText(getBaseContext(),"display logging", Toast.LENGTH_SHORT).show();
}
here is my CheckActivity.java
(when i receive data, my purpose is that store data to the server. therefore, i don't need to use layout. So, in order to check data, i use toast "hello". but toast never popup my phone...)
public class CheckActivity extends Activity {
private static final String TAG = "CheckActivity";
private Intent intent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_check);
intent = new Intent(this, RecoBackgroundRangingService.class);
Toast.makeText(getBaseContext(), "check activity", Toast.LENGTH_SHORT).show();
}
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateUI(intent);
}
};
#Override
public void onResume() {
super.onResume();
startService(intent);
registerReceiver(broadcastReceiver, new IntentFilter(RecoBackgroundRangingService.BROADCAST_ACTION));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
stopService(intent);
}
private void updateUI(Intent intent) {
int status = intent.getIntExtra("status", -1);
Toast.makeText(getBaseContext(), "hello", Toast.LENGTH_SHORT).show();
}
}
I built app to play audio from internet, I use service to play audio in background, the question is how to show loding dialog while media player is in preparing posision in service(background) hire my Code.
Activity
package com.uqifm.onlineradio;
.......
public class MainActivity extends AppCompatActivity {
Button b_play;
Boolean started = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b_play = (Button) findViewById(R.id.b_play);
b_play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(started){
started = false;
stopService(new Intent(MainActivity.this,MyService.class));
b_play.setText("PLAY");
}else{
started = true;
startService(new Intent(MainActivity.this,MyService.class));
b_play.setText("STOP");
}
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
stopService(new Intent(MainActivity.this,MyService.class));
}
}
Service
package com.uqifm.onlineradio;
....................
public class MyService extends Service {
MediaPlayer mediaPlayer;
String stream = "http://xxxxx:36365";
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(stream);
mediaPlayer.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mediaPlayer.start();
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
mediaPlayer.release();
}
}
Register broadcasts, Start a ProgressDialog before you start the service. Then wait for the broadcast. After the broadcast, hide the dialog. see example in this thread. Send data from Service back to my activity
Put a ProgressDialog in xml and set the visibility according to your requirement. Use interface for communicating with service.
You can use Broadcast or try EventBus which is much more easier. You can post an event from the service using EventBus and receive the the broadcast in MainActivity and update the progress dialogue.
Please follow the link.
Maybe something like this:
fun playAudio(audioUrl: String){
showProgressBar()
var mediaPlayer: MediaPlayer? = MediaPlayer().apply {
setAudioStreamType(AudioManager.STREAM_MUSIC)
setDataSource(audioUrl)
prepareAsync() // might take long! (for buffering, etc)
}
mediaPlayer?.setOnPreparedListener {
hideProgressBar()
it.start()
}
mediaPlayer?.setOnCompletionListener {
mediaPlayer.release()
}
}
This question already has an answer here:
Want to Access Power Button events in android [duplicate]
(1 answer)
Closed 4 years ago.
I am developing an application in which call on an number on power button click (4 times) but now issue is when user press home button 4 times it will trigged the call and I want only side power button click.
My receiver and service in manifest
<receiver
android:name=".services.SOSBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
<service
android:name=".services.SOSService"
android:enabled="true">
</service>
and my BroadcastReceiver class
public class SOSBroadcastReceiver extends BroadcastReceiver
{
private static long lastTriggerTime = 0;
private static final int ONE_MILLI = 1000;
protected static final long ONE_SEC = 1 * ONE_MILLI;
protected static final long TWO_SEC = 2 * ONE_MILLI;
protected static final long THREE_SEC = 3 * ONE_MILLI;
protected static final int TRIGGER_THRESHOLD = 3;
protected static boolean triggerInProgress = false;
protected static int triggerCounter = 0;
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().contains(Intent.ACTION_SCREEN_ON))
{
if (!triggerInProgress)
{
checkAndCreateAlert(context);
}
}
else if (intent.getAction().contains(Intent.ACTION_SCREEN_OFF))
{
if (!triggerInProgress)
{
checkAndCreateAlert(context);
}
}
}
private void checkAndCreateAlert(Context context)
{
/*---- If the gap between power button press is less than 2 seconds ----*/
if ((System.currentTimeMillis() - lastTriggerTime) <= TWO_SEC
|| (triggerCounter == 0))
{
triggerCounter++;
lastTriggerTime = System.currentTimeMillis();
}
else
{
triggerCounter = 0;
}
if (triggerCounter > TRIGGER_THRESHOLD)
{
((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(1000);
triggerInProgress = true;
Intent intent = new Intent(context, SOSActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("timer", true);
context.startActivity(intent);
triggerInProgress = false;
triggerCounter = 0;
}
}
}
My code will keep the count of power button click in terms of screen_on and screen_off event and execute the other method if power button is pressed more than 3 time in 2secs.
This is my Service class
public class SOSService extends Service
{
BroadcastReceiver mReceiver;
IntentFilter pqrs_intentFilter;
#Override
public IBinder onBind(Intent intent)
{
return null;
}
#Override
public void onCreate()
{
super.onCreate();
}
#Override
public void onDestroy()
{
unregisterReceiver(mReceiver);
}
#Override
public void onStart(Intent intent, int startid)
{
pqrs_intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
pqrs_intentFilter.addAction(Intent.ACTION_SCREEN_ON);
mReceiver = new SOSBroadcastReceiver();
registerReceiver(mReceiver, pqrs_intentFilter);
}
public void onStop(Intent intent)
{
unregisterReceiver(mReceiver);
}
}
public class ExampleActivity extends Activity {
#Override
protected void onCreate() {
// INITIALIZE RECEIVER
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
// YOUR CODE
}
#Override
protected void onPause() {
// WHEN THE SCREEN IS ABOUT TO TURN OFF
if (ScreenReceiver.wasScreenOn) {
// THIS IS THE CASE WHEN ONPAUSE() IS CALLED BY THE SYSTEM DUE TO A SCREEN STATE CHANGE
System.out.println("SCREEN TURNED OFF");
} else {
// THIS IS WHEN ONPAUSE() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
}
super.onPause();
}
#Override
protected void onResume() {
// ONLY WHEN SCREEN TURNS ON
if (!ScreenReceiver.wasScreenOn) {
// THIS IS WHEN ONRESUME() IS CALLED DUE TO A SCREEN STATE CHANGE
System.out.println("SCREEN TURNED ON");
} else {
// THIS IS WHEN ONRESUME() IS CALLED WHEN THE SCREEN STATE HAS NOT CHANGED
}
super.onResume();
}
}
Receiver
public class ScreenReceiver extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
}
Intent i = new Intent(context, UpdateService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
}
}
Service
public static class UpdateService extends Service {
#Override
public void onCreate() {
super.onCreate();
// REGISTER RECEIVER THAT HANDLES SCREEN ON AND SCREEN OFF LOGIC
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public void onStart(Intent intent, int startId) {
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if (!screenOn) {
// YOUR CODE
} else {
// YOUR CODE
}
}
}
Hopefully this was useful. Let me know if you have questions.
I am trying to learn Android services, but having a little bit of trouble.
I have a simple service with a MediaPlayer which plays some streams from the internet. I bind the service to my MainActivity, set an URL on the service and start playing the stream. This works fine. The service immediately becomes a foreground service with a notification. I can successfully change URL's from the MainActivity and subsequently start a new stream. However, there are a couple of things I want to implement.
I do not want a notification when the MainActivity is visible to the user, only when the user presses the home button or back button I want the service to start playing in the foreground. When the user clicks on the notification I want the MainActivity to reopen and the stream uninterrupted. Does this mean my MainActivity can never be destroyed?
As of now, when I press the home button the stream keeps playing and clicking the notification makes the MainActivity recreate the service (the stream stops and starts to play again). I actually want the Service to never stop playing unless the user kills the app by swiping it in the multitasking window (like Spotify does it).
My service code is as follows:
public class StreamService extends Service implements
MediaPlayer.OnPreparedListener, MediaPlayer.OnErrorListener,
MediaPlayer.OnCompletionListener {
private MediaPlayer player;
private final IBinder musicBind = new StreamBinder();
private StreamInfo mCurrentStream;
private static final int NOTIFY_ID = 1;
public void onCreate() {
super.onCreate();
initMusicPlayer();
}
public void initMusicPlayer() {
player = new MediaPlayer();
player.setWakeMode(getApplicationContext(),
PowerManager.PARTIAL_WAKE_LOCK);
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setOnPreparedListener(this);
player.setOnCompletionListener(this);
player.setOnErrorListener(this);
}
public class StreamBinder extends Binder {
public StreamService getService() {
return StreamService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return musicBind;
}
#Override
public boolean onUnbind(Intent intent) {
player.stop();
player.release();
return false;
}
public void playStream() {
player.reset();
try {
player.setDataSource(this, mCurrentStream.getUrl());
} catch (Exception e) {
Log.e("MUSIC SERVICE", "Error setting data source", e);
}
player.prepareAsync();
}
public void setStream(StreamInfo stream) {
mCurrentStream = stream;
}
#Override
public void onCompletion(MediaPlayer mp) {
}
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mp.reset();
return false;
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
Intent notIntent = new Intent(this, MainActivity.class);
notIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendInt = PendingIntent.getActivity(this, 0,
notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification.Builder builder = new Notification.Builder(this);
builder.setContentIntent(pendInt)
.setSmallIcon(R.drawable.ic_action_navigation_chevron_right)
.setTicker(mCurrentStream.getTitle())
.setOngoing(true)
.setContentTitle("Playing")
.setContentText(mCurrentStream.getTitle());
Notification not = builder.build();
startForeground(NOTIFY_ID, not);
}
#Override
public void onDestroy() {
stopForeground(true);
}
}
And my MainActivity:
public class MainActivity extends AppCompatActivity implements ServiceConnection {
private static final String TAG = MainActivity.class.getSimpleName();
private StreamService mStreamService;
private boolean musicBound = false;
private Intent playIntent;
#Override
protected void onStart() {
super.onStart();
if (playIntent == null) {
playIntent = new Intent(this, StreamService.class);
bindService(playIntent, this, MainActivity.BIND_AUTO_CREATE);
startService(playIntent);
}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startStreaming();
}
private void startStreaming() {
mStreamService.setStream(getSelectedStream());
mStreamService.playStream();
}
#Override
protected void onDestroy() {
stopService(playIntent);
mStreamService = null;
super.onDestroy();
}
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
StreamService.StreamBinder binder = (StreamService.StreamBinder) service;
mStreamService = binder.getService();
musicBound = true;
startStreaming();
}
#Override
public void onServiceDisconnected(ComponentName name) {
musicBound = false;
}
public StreamInfo getSelectedStream() {
//Returns some stream from a widget
}
}
Of course there is a widget in my MainActivity with a listener and when the selection changes the startStreaming() method is called.
Can anyone point me in the right direction?
I do not want a notification when the MainActivity is visible to the
user, only when the user presses the home button or back button I want
the service to start playing in the foreground.
Keep a boolean flag in your Service to indicate if something is bound to it. Check the flag before displaying the notification. So for example:
#Override
public IBinder onBind(Intent intent) {
mBound = true;
hideNotifications();
return musicBind;
}
#Override
public void onRebind(Intent intent) {
mBound = true;
hideNotifications();
}
When the user clicks
on the notification I want the MainActivity to reopen and the stream
uninterrupted. Does this mean my MainActivity can never be destroyed?
You need to unbind your activity onStop().
As of now, when I press the home button the stream keeps playing and
clicking the notification makes the MainActivity recreate the service
(the stream stops and starts to play again). I actually want the
Service to never stop playing unless the user kills the app by swiping
it in the multitasking window (like Spotify does it).
onStart() of your Activity check if service is running and rebind to it instead of recreating it. If it's not running - create and bind.