Ok so this is the problem. I do context.startService(serviceIntent), but i don't get new log message from OnCreate or OnStartCommand.
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.distorted.flashnotifier"
android:versionCode="0"
android:versionName="0.6" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.distorted.flashnotifier.Home"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="FlashService"
android:exported="true"
android:enabled="true"
android:permission="android.permission.READ_PHONE_STATE">
</service>
</application>
</manifest>
What i already tried:
Changing service name to ".FlashService" and "com.distorted.flashnotifier.FlashService"
Activity code:
private Context cont;
protected void onCreate(Bundle savedInstanceState) {
cont = getApplicationContext();
}
public void setNotificator() {
Intent serviceIntent = new Intent(cont, FlashService.class);
if(callNotificator){
cont.startService(serviceIntent);
Log.d("LOG", "setNotificator works");
} else {
cont.stopService(serviceIntent);
}
}
What have i tried:
changing all "cont" to "this"
startService(new Intent(cont, FlashService.class));
FlashService.class:
package com.distorted.flashnotifier;
public class FlashService extends Service{
public void OnCreate () {
Log.d("LOG", "onCreate works");
}
public int OnStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
I tried:
moving Log.d to onStartCommand
changed START_STICKY to super.onStartCommand(intent, flags, startId)
Ok so I get that setNotificator log message, but not the onCreate one.
Does anyone know how could I make this work? (Thanks for reading the whole thing).
LogCat doesn't say anything interesting.
UPDATE:
full Activity code:
package com.distorted.flashnotifier;
import java.util.Calendar;
import android.app.Activity;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.Switch;
import android.widget.TimePicker;
import android.widget.Toast;
import android.app.TimePickerDialog;
import android.content.Context;
import android.content.Intent;
public class Home extends Activity {
private Button timeSelectBut1;
private Button timeSelectBut2;
private int hour1;
private int hour2;
private int minute1;
private int minute2;
static final int TIME_DIALOG_ID1 = 1;
static final int TIME_DIALOG_ID2 = 2;
private Switch callSwitch;
private Switch notificationSwitch;
private boolean callNotificator;
private boolean notifNotificator;
private Context cont;
//IMPORTANT UNTIL timeSelectBut1.setOnClickListener
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
cont = getApplicationContext();
timeSelectBut1 = (Button) findViewById(R.id.selectTimeButton1);
timeSelectBut1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(TIME_DIALOG_ID1);
}
});
final Calendar cal1 = Calendar.getInstance();
hour1 = cal1.get(Calendar.HOUR_OF_DAY);
minute1 = cal1.get(Calendar.MINUTE);
updateText(1);
timeSelectBut2 = (Button) findViewById(R.id.selectTimeButton2);
timeSelectBut2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
showDialog(TIME_DIALOG_ID2);
}
});
final Calendar cal2 = Calendar.getInstance();
hour2 = cal2.get(Calendar.HOUR_OF_DAY);
minute2 = cal2.get(Calendar.MINUTE);
updateText(2);
}
#Override
protected Dialog onCreateDialog(int id){
if (id == 1) {
return new TimePickerDialog(this, mTimeSetListener1, hour1, minute1, true);
}
if (id == 2) {
return new TimePickerDialog(this, mTimeSetListener2, hour2, minute2, true);
}
return null;
}
public void updateText(int id) {
if (id == 1) timeSelectBut1.setText(pad(hour1) + ":" + pad(minute1));
if (id == 2) timeSelectBut2.setText(pad(hour2) + ":" + pad(minute2));
}
private TimePickerDialog.OnTimeSetListener mTimeSetListener1 = new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
hour1 = hourOfDay;
minute1 = minute;
updateText(1);
}
};
private TimePickerDialog.OnTimeSetListener mTimeSetListener2 = new TimePickerDialog.OnTimeSetListener() {
public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
hour2 = hourOfDay;
minute2 = minute;
updateText(2);
}
};
private static String pad(int c) {
if (c >= 10)
return String.valueOf(c);
else
return "0" + String.valueOf(c);
}
//IMPORTANT
public void onCallSwitchClicked(View view) {
boolean on = ((Switch) view).isChecked();
if (on) {
callNotificator = true;
setNotificator();
//timeSelectBut1.setText("callNotifTrue");
} else {
callNotificator = false;
setNotificator();
//timeSelectBut1.setText("callNotifFalse");
}
}
public void onNotifSwitchClicked(View view) {
boolean on = ((Switch) view).isChecked();
if (on) {
notifNotificator = true;
//setNotificator();
} else {
notifNotificator = false;
//setNotificator();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
//IMPORTANT
public void setNotificator() {
Intent serviceIntent = new Intent(this, FlashService.class);
if(callNotificator){
startService(serviceIntent);
Log.d("LOG", "SetNotificator works");
} else {
stopService(serviceIntent);
}
}
}
You did not register the service properly. Delete the line android:permission in service
Replace your manifest by this.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.distorted.flashnotifier"
android:versionCode="0"
android:versionName="0.6" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.distorted.flashnotifier.Home"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".FlashService"
android:exported="true"
android:enabled="true"
>
</service>
</application>
</manifest>
EDIT:
After trying your code I realized that, you did not override oncreate and onstartcommand properly. In Names of the method onCreate() and onStartCommand() , o is not caps.. Please change it to small o and try.
Since you are starting your Service from Activity, the correct code is:
public void setNotificator() {
Intent serviceIntent = new Intent(this, FlashService.class);
if(callNotificator){
startService(serviceIntent);
Log.d("LOG", "setNotificator works");
} else {
stopService(serviceIntent);
}
}
Moving forward, per Docs: The system calls this method when the service is first created, to perform one-time setup procedures (before it calls either onStartCommand() or onBind()). If the service is already running, this method is not called.
So I'll better put Log call to the onStartCommand
And your service is using permission, again from Docs: If a caller of startService(), bindService(), or stopService(), has not been granted this permission, the method will not work and the Intent object will not be delivered to the service. If this attribute is not set, the permission set by the <application> element's permission attribute applies to the service. If neither attribute is set, the service is not protected by a permission.
Related
I am trying to get phone state using TelephoneManager class and using a job scheduler i have assigned a listener for onCallStateChangeListener() ... but still android 9 "Pie" kills every background task like my listener and jobScheduler ! so how can i solve this problem and get phone state while my app is in totally closed !
Note : I tried an app like Truecaller and it works just fine after closing the app! how can i get similar behavior on my app ?
MainActivity.java
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ComponentName;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final int JOB_ID = 123;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
scheduleJob();
}
public void scheduleJob() {
ComponentName componentName = new ComponentName(this, ExampleJobService.class);
JobInfo info = new JobInfo.Builder(JOB_ID , componentName)
.setPersisted(true)
.setPeriodic(15 * 60 * 1000)
.build();
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
int resultCode = scheduler.schedule(info);
if (resultCode == JobScheduler.RESULT_SUCCESS) {
Log.d(TAG, "Job scheduled");
} else {
Log.d(TAG, "Job scheduling failed");
}
}
public void cancelJob() {
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.cancel(123);
Log.d(TAG, "Job cancelled");
}
}
JobScheduler.java
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Context;
import android.os.Looper;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
public class ExampleJobService extends JobService {
private static final String TAG = "ExampleJobService";
boolean quitLooper;
TelephonyManager telephonyManager;
public void checkForIncomingCalls() {
telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
new Thread(new Runnable() {
#Override
public void run() {
quitLooper = false;
Looper.prepare();
PhoneStateListener callStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String phoneNumber) {
if(state==TelephonyManager.CALL_STATE_RINGING){
Toast.makeText(getApplicationContext(),"Phone Is Riging",
Toast.LENGTH_LONG).show();
}
if(state==TelephonyManager.CALL_STATE_OFFHOOK){
Toast.makeText(getApplicationContext(),"Phone is Currently in A call",
Toast.LENGTH_LONG).show();
}
if(state==TelephonyManager.CALL_STATE_IDLE){
Toast.makeText(getApplicationContext(),"phone is neither ringing nor in a call",
Toast.LENGTH_LONG).show();
}
}
};
telephonyManager.listen(callStateListener , PhoneStateListener.LISTEN_CALL_STATE);
Looper.loop();
}
}).start();
}
#Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "Job started");
doBackgroundWork(params);
return true;
}
private void doBackgroundWork(final JobParameters params) {
new Thread(new Runnable() {
#Override
public void run() {
checkForIncomingCalls();
Log.d(TAG, "Job finished");
jobFinished(params, false);
}
}).start();
}
#Override
public boolean onStopJob(JobParameters params) {
Log.d(TAG, "Job cancelled before completion");
return true;
}
}
Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.devteam.test231">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ExampleJobService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
</application>
</manifest>
Thanks!
I Could not figure out what is wrong with below code. I also checked about registering receiver twice. But that's also not the case. or may be I am missing something.
Could any please help. I really need it. :(
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.IBinder;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.widget.Toast;
/**
*
* #author Bharat
*
*/
public class CallNotifierService extends Service
{
private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
private CallBr br_call;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public void onDestroy()
{
Log.d("service", "destroy");
this.unregisterReceiver(this.br_call);
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_OUT);
filter.addAction(ACTION_IN);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
return START_NOT_STICKY;
}
public class CallBr extends BroadcastReceiver
{
Bundle bundle;
String state;
String inCall, outCall;
public boolean wasRinging = false;
public boolean answered = false;
public boolean outgoing = false;
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(ACTION_IN))
{
if ((bundle = intent.getExtras()) != null)
{
state = bundle.getString(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
{
inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
wasRinging = true;
Toast.makeText(context, "Incoming Call : " + inCall, Toast.LENGTH_LONG).show();
}
else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
{
if (wasRinging == true)
{
answered = true;
Toast.makeText(context, "Answered", Toast.LENGTH_LONG).show();
}
}
else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE))
{
wasRinging = false;
Toast.makeText(context, "Disconnected", Toast.LENGTH_LONG).show();
}
}
}
else if (intent.getAction().equals(ACTION_OUT))
{
if ((bundle = intent.getExtras()) != null)
{
outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "Outgoing Call : " + outCall, Toast.LENGTH_LONG).show();
outgoing = true;
}
}
}
}
}
Below is the activity I am calling it from
public class MyActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.roaming);
Intent intent = new Intent(this, CallNotifierService.class);
startService(intent);
}
.
.
.
}
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ind.cosmos.main"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-sdk
android:minSdkVersion="22"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<!-- android:theme="#style/AppTheme"> -->
<activity
android:name="ind.cosmos.main.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="ind.cosmos.callRecord.CallNotifierService" />
</application>
As Bharat said it's better so handle it in code. Below is a trick to do so, found here, thanks to Michael Marvick who has given detail description as well.
public class PhoneStateBroadcastReceiver extends BroadcastReceiver {
public static final String TAG = "PHONE STATE";
private static String mLastState;
#Override
public void onReceive(Context context, Intent intent) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (!state.equals(mLastState)) {
mLastState = state;
Log.e(TAG, state);
}
}
}
Actually .. there is nothing wrong with the code. its System who triggers this. some time its 2 times.. other times it touches 4 times.
So the best we can do it handle it in the code itself.
I have the same behavior, and there is no issue in your code. android.intent.action.PHONE_STATE can be received few times, but Intent's bundle is always different, for example:
D/App(2001): Bundle{ state => OFFHOOK; subscription => 1; }Bundle
D/App(2001): Bundle{ incoming_number => 555555555; state => OFFHOOK; subscription => 9223372036854775807; }Bundle
My Requirment
I am trying to build an application which shows a Toast whenever user makes a outgoing call from the phone. For this I am using a BroadcastReceiver to tap the call action and a service (to run Receiver always). once I start this activity, it starts showing toast when a outgoing call get initiated ...everything works well.
Issues
Sometimes I dont get any Toast Action EVEN for Outgoing call as well, is that mean service stops after some time ?
After phone reboot Toast Action for Outgoing call stops. Untill you start the servce again manually.
The code I have written is ok ? OR can it be improved ?
Below is the complete code -
MainActivity.class
public class MainActivity extends Activity
{
CallNotifierService m_service;
boolean isBound = false;
private ServiceConnection m_serviceConnection = new ServiceConnection()
{
#Override
public void onServiceConnected(ComponentName className, IBinder service)
{
m_service = ((CallNotifierService.MyBinder)service).getService();
Toast.makeText(MainActivity.this, "Service Connected", Toast.LENGTH_LONG).show();
isBound = true;
Intent intent = new Intent(MainActivity.this, CallNotifierService.class);
startService(intent);
}
#Override
public void onServiceDisconnected(ComponentName className)
{
m_service = null;
isBound = false;
}
};
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, CallNotifierService.class);
bindService(intent, m_serviceConnection, Context.BIND_AUTO_CREATE);
}
.
.
.
}
CallNotifierService.class
public class CallNotifierService extends Service
{
private final IBinder myBinder = new MyBinder();
private static final String ACTION_OUTGOING_CALL = "android.intent.action.NEW_OUTGOING_CALL";
private static final String ACTION_ANSWER = "android.intent.action.ANSWER";
private static final String ACTION_CALL = "android.intent.action.CALL";
private CallBr br_call;
#Override
public IBinder onBind(Intent arg0)
{
return myBinder;
}
#Override
public void onDestroy()
{
Log.d("service", "destroy");
this.unregisterReceiver(this.br_call);
Toast.makeText(CallNotifierService.this, "Receiver Un-Registered", Toast.LENGTH_LONG).show();
super.onDestroy();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_ANSWER);
filter.addAction(ACTION_CALL);
filter.addAction(ACTION_OUTGOING_CALL);
this.br_call = new CallBr();
this.registerReceiver(this.br_call, filter);
Toast.makeText(CallNotifierService.this, "onStartCommand Called", Toast.LENGTH_LONG).show();
return START_STICKY;
}
public class MyBinder extends Binder
{
CallNotifierService getService()
{
return CallNotifierService.this;
}
}
public class CallBr extends BroadcastReceiver
{
public CallBr() {}
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Action:"+intent.getAction(), Toast.LENGTH_LONG).show();
}
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.alwaysrunningprocesswithcallanswertap"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-sdk
android:minSdkVersion="22"
android:targetSdkVersion="22" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.example.alwaysrunningprocesswithcallanswertap.CallNotifierService" />
</application>
</manifest>
Could anyone please help for the issue OR pointout something better ?
#Bharat Once device switch off automatically service will stop, So when ever your device reboot that time you need to start service again then only you will get Toast Action, refer this example code :
BootCompleteReceiver.java
package com.example.newbootservice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class BootCompleteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, AutostartService.class);
context.startService(service);
}
}
AutostartService .java
package com.example.newbootservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class AutostartService extends Service {
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service Destroy", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
}
MainActivity.java
package com.example.newbootservice;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startService(new Intent(getBaseContext(), AutostartService.class));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
Manifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.newbootservice"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<service android:name=".AutostartService"/>
<receiver android:name=".BootCompleteReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
How can I know if the Power button is Pressed while Activity is Closed, not screen on/off because I want to know exactly how many times Power button is Pressed.
I think I have use Broadcast or Service, but I can't find any solutions that work for me, I don't know what should I do. Here are some solutions I found but not work.
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
Log.d("#tag", "ACTION_Down ");
}
return super.onKeyDown(keyCode, event);
}
Manifest
<uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
or this, but I don't need it because It work only screen on/off, if I fast double click Power button when screen Off then It not work.
public class PowerBroadcast extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
screenOff = true;
Toast.makeText(context, "ACTION_SCREEN_OFF ", Toast.LENGTH_SHORT).show();
Log.d("#tag", "ACTION_SCREEN_OFF ");
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
screenOff = false;
Toast.makeText(context, "ACTION_SCREEN_ON", Toast.LENGTH_LONG).show();
Log.d("#tag", "ACTION_SCREEN_On ");
}
}
}
check this out :
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("", "Dispath event power");
//do watever u want.
return true;
}
return super.dispatchKeyEvent(event);
}
or try the hole code :
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.userpresent"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.userpresent.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.example.userpresent.LockService" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</service>
</application>
</manifest>
MainActivity.java
package com.example.userpresent;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService(new Intent(getApplicationContext(), LockService.class));
}
}
LockService.java
package com.example.userpresent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
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;
}
}
}
ScreenReceiver.java
package com.example.userpresent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(final Context context, final Intent intent) {
Log.e("LOB","onReceive");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// do whatever you need to do here
wasScreenOn = false;
Log.e("LOB","wasScreenOn"+wasScreenOn);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// and do whatever you need to do here
wasScreenOn = true;
}else if(intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
Log.e("LOB","userpresent");
Log.e("LOB","wasScreenOn"+wasScreenOn);
//do something.
}
}
}
I have an Activity class, in which I have a static flag, let's say
public static volatile flag = false;
Then in the class, I start a thread, which checks the flag and do different things.
I also have a broadcastreceiver, which sets the flag to true or false.
I though volatile will force the flag to the most recent value. But I can see my broadcastreceiver sets the static flag to true, but my thread is still getting it as false.
Am I missing something basic here? Any help would be appreciated!
Simplified Code (Updated) - So the flag is supposed to change to true after one minute. But it never did. But message from broadcast receiver shows it has been change to true
TestappActivity.java:
package com.test;
import java.util.Calendar;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
public class TestappActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent intent0 = new Intent(this, TestService.class);
this.startService(intent0);
Intent intent = new Intent(this, TestReceiver.class);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
PendingIntent sender = PendingIntent.getBroadcast(this,
1, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Calendar slot = Calendar.getInstance();
int min = slot.get(Calendar.MINUTE);
slot.set(Calendar.MINUTE, min+1);
am.set(AlarmManager.RTC_WAKEUP, slot.getTimeInMillis(), sender);
}
}
TestService.java:
package com.test;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class TestService extends Service {
private static final String TAG = "TestService";
public static volatile boolean flag = false;
private MyTopThread mTopThread;
public TestService() {
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
}
#Override
public void onDestroy() {
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
protect();
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
/**
* Run protection
*
*/
private void protect() {
mTopThread = new MyTopThread();
mTopThread.start();
}
private class MyTopThread extends Thread {
#Override
public void run() {
while (true) {
try {
Thread.sleep(150);
Log.d(TAG, "Flag is " + TestService.flag);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
TestReceiver.java:
package com.test;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class TestReceiver extends BroadcastReceiver {
final static private String TAG = "TestReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive is triggered ...");
TestService.flag = true;
Log.d(TAG, "flag is changed to " + TestService.flag);
}
}
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="8" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".TestappActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".TestService" />
<receiver
android:name=".TestReceiver"
android:process=":remote" >
</receiver>
</application>
</manifest>
I think the problem is that you are running the receiver in its own process. From the docs for the android:process attribute of <receiver>:
If the name assigned to this attribute begins with a colon (':'), a new process, private to the application, is created when it's needed and the broadcast receiver runs in that process.
I think the receiver is modifying a process-local version of TestService.flag, not the one being used by TestService. Try removing the android:process attribute from the <receiver> tag in your manifest.
From this link
http://www.javamex.com/tutorials/synchronization_volatile.shtml
Essentially, volatile is used to indicate that a variable's value will
be modified by different threads.
I really hope your service thread is not this one (I don't see any other one):
private class MyTopThread extends Thread {
#Override
public void run() {
while (true) {
try {
Thread.sleep(150);
Log.d(TAG, "Flag is " + TestService.flag);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Because you have while(true) here, not while(!flag) as it should be.