keep vibrator running in sleep mode - java

I'm trying to keep the vibrator run even after sleep mode (screen locks), but the app won't work.I don't know what i'm missing..
Is there any solutions other than Wake Lock,and BroadcastReceiver?
(NO prejudgements please,it's vibrate once every 4:57 minutes)
public class MainActivity extends Activity {
public BroadcastReceiver vibrateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {0, 3000, 297000};
v.vibrate(pattern, 0);
}
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
}

First of all create your service scheduler based on for instance alarm service. Sth. like that.
public class ScheduledLocalisationExecutor {
private Context context;
private AlarmManager alarmManager;
private Intent broadcastIntent;
private PendingIntent pendingIntent;
private DbxStart dbxStart;
public ScheduledLocalisationExecutor(Context appContext) {
context = appContext;
dbxStart = new DbxStart();
}
public void setUpScheduledService(long updateTime) {
if (dbxStart.getOpenedDatastore() == null) {
Log.e("DROPBOX", "Dropbox account is not linked...");
return;
}
Log.w("scheduled factory","updating Service!");
broadcastIntent = new Intent(context, LocalisationUpdatesReceiver.class);
pendingIntent = PendingIntent.getBroadcast(context, 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + updateTime, pendingIntent);
}
}
Now register your broadcast receiver in android manifest.
<receiver android:name=".receivers.LocalisationUpdatesReceiver">
</receiver>
And create your broadcast receiver.
public class LocalisationUpdatesReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long[] pattern = {0, 3000, 297000};
v.vibrate(pattern, 0);
}
}
}
Follow that scheme and you will succeed!

BroadcastReceiver.onReceive() is not designed for long operations. You should call vibrate() somewhere else (in a Service or better an IntentService, for that matter).
Also, the vibration pattern takes too long to run. If I was you, I'd schedule vibrate() to run a short pattern every 4:57 via Android's scheduling mechanism, called AlarmManager. The idea is, write a BroadcastReceiver.onReceive() that calls startService(yourservice) and schedule that BroadcastReceiver to be run each time (or better, since you will need a partial wake lock to circumvent sleep mode write a WakefulBroadcastReceiver.onReceive() that calls startWakefulService()). Don't forget to call YourWakefulBroadcastReceiver.completeWakefulIntent() at the end of your service to release the wake lock.
If you still want your service to execute a vibration pattern that runs that long, the idea is the same.

Just wanted to add the information that you can give the user a distinct and unique haptic effect by using the free haptic effect library from Immersion Corp. That will help the user understand that this is coming from your app, and not a regular notification etc (without needing a 3 second long buzz).
That library contains 120+ fine-tuned haptic effects, and you can download it from here with a quickstart guide to linking the library and calling it over here.

Related

How to properly add new Activity onto top of the stack after tapping notification

I'm writing a really big app with plenty of activities. I have one class running in the background that is checking are there any changes on the server and perform appropriate action. One of the actions is to send notification to user about employee's clock in, out and similar. That kind of notification is clickable, and it should open employee's contact page PeopleSingleScene_Activity, and that is working as expected. However, when I click back button, application quits (no parent activities).
Code for creating notification with pending intent is as following:
public void sendEmployeeWorkNotification(String ticker, String title, String text, String loc, int employee_id) {
PendingIntent pendingIntent;
Intent intent;
Context currentContext = G.context;
if (loc.equals("LOC")) {
intent = new Intent(currentContext, PeopleSingleScene_Activity.class);
intent.putExtra("people_id", employee_id);
pendingIntent = PendingIntent.getActivity(currentContext, 0, intent, 0);
} else {
//some other actions
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(currentContext, CHANNEL_ID)
.setSmallIcon(R.drawable.vector_notif)
.setTicker(ticker)
.setContentTitle(title)
.setContentText(text)
.setColor(ContextCompat.getColor(currentContext, R.color.rcOutcome))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(text))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(currentContext);
notificationManager.notify(G.simpleMessageCounter, builder.build());
simpleSong(R.raw.notificationsimple);
G.simpleMessageCounter++;
}
G.context is the last activity context opened... It is a static variable in global class G. I'm creating it in a way:
public class SomeActivityClass extends AppCompatActivity {
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.some_layout);
G.context = this;
....
}
....
}
I have also tried with context from my App class for retrieving string values or anything else with a context in classes without activities ...
public class App extends Application {
private static Context mContext;
#Override
public void onCreate() {
super.onCreate();
mContext = this;
}
public static Context getContext(){
return mContext;
}
public static String getStr(int resid) {
return mContext.getResources().getString(resid);
}
}
When I use this context from App.getContext(); result is the same, after tapping back button, application quits.
Question is: Is there a problem with a context for creating pending intent and notification, or there is an issue with intent creation flags? I have tried lot of combinations with contexts and flags, but none of them works. And I cannot write (or I don't know maybe) some listeners on each activity to listen for this kind of event and open new intent from itself. There will be over 50 activities...
You have to make launch mode for this activity single top <activity android:launchMode="singleTop" />
Read more about Android Activity Launch Mode
Finally found a solution, thanks to my buddy Miljan.
When creating pendingIntent, just needed a proper flag. So instead of
pendingIntent = PendingIntent.getActivity(currentContext, 0, intent, 0);
just put a flag
pendingIntent = PendingIntent.getActivity(currentContext, 0, intent, PendingIntent.FLAG_ONE_SHOT);
and it works regularly. I can go back to previous activity after displaying activity intitiated by tapping notification.

Encapsulating alarm creation code in a different class than the Activity

I'm creating my first Android Notifications app, so I'm very much a beginner. I have a class, Notification.java, that asks the user for the time and date. Using these data, it creates an alarm that is triggered at the specified date and time.
Here is my code for Notification.java
public class Notification extends Activity {
private PendingIntent pendingIntent;
private SetAlarm alarm;
private Date date;
private Time time;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm);
findViewById(R.id.setTime).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setAlarmTime();
}
});
findViewById(R.id.setDate).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setAlarmDate();
}
});
findViewById(R.id.checkBox).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
createAlarm();
}
});
}
private void setAlarmTime() {
}
private void setAlarmDate() {
}
private void createAlarm() {
alarm = new SetAlarm();
}
}
The createAlarm() method is supposed to actually create the alarm using the information that the user has provided (i.e. time and date). However, I understand that I need the following code block to create the alarm?
private void setTheAlarm() {
Intent alarmIntent = new Intent(SetAlarm.this, AlarmReceiver.class);
pendingIntent = PendingIntent.getBroadcast(SetAlarm.this, 0, alarmIntent, 0);
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
int interval;
/* Set the alarm to the date specified by user */
/* Repeating on every x minutes interval */
}
However, the Notification.java is where I am extending 'Activity'. It is also where I have the 'pendingIntent; code.
So essentially, how can I move the alarm creation code into a separate class when the code dealing with the Activity is in an entirely different class?
Thanks for the help. I hope my question is clear enough.
Not exactly clear if that is what you want, but if I understand you correct, you need the alarmManager inside an extra class to reach it from everywhere? You could make a static one like this:
public class MyAlarmManager{
private static AlarmManager mAlarmManager;
private static PendingIntent mPendingIntent;
//start alarm
public static void setAlarm(Context context, int alarmId, long alarmTime) {
if (mAlarmManager== null) {
mAlarmManager= (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
Intent startAlarmIntent = new Intent(context, YouReceiver.class);
if(mPendingIntent==null){
mPendingIntent = PendingIntent.getBroadcast(context, alarmId,
startAlarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
//check the version because of doze mode since MM
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
alarmTime, mPendingIntent);
} else {
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mPendingIntent);
}
}
//stop alarm
public static void stopAlarm(Context context, int id) {
if (mAlarmManager == null) {
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
Intent stopAlarmIntent = new Intent(context, YourReceiver.class);
if(mPendingIntent==null){
mPendingIntent= PendingIntent.getBroadcast(context, id, stopAlarmIntent, 0);
}
mAlarmManager.cancel(mPendingIntent);
mPendingIntent.cancel();
}
}
Then you can call it like:
MyAlarmManager.setAlarm(this, id, interval);
and stop it:
MyAlarmManager.stopAlarm(this, id);
You can do this from every class by passing the context and the identical id . The alarm id must be the same as you passed by starting the alarm, otherwise it will not work. Notice that above MarshMallow, there are some changes for AlarmManager and it´s possible that it does not work in every case. If your app get´s killed or goes into idle mode, the alarm won´t be triggered in every circumstance. To handle doze mode, see this:https://developer.android.com/training/monitoring-device-state/doze-standby.html
And be aware of any third party app and battery managers, that could kill your app. Also, Huawei devices have their own battery management besides the doze mode.
If this is not what you wanted, come back. Can´t guarantee that there is no error because I have overseen something, it´s from scratch.

Creating a background service that launches an app at a specific time.

I just started on android development and I'm trying to write and a service that runs in the background and will launch an app at a specific time.
The program I wrote is based on a tutorial I came across, basically the app has 2 buttons, a start and stop. Once the user presses the start button, it'll start the background service and will check the time and if the time is right, it'll launch the app.
However I noticed that it doesn't always checks the time, it only does it when the user presses the button. How do I make it so that, it'll keep checking the time, once the user presses the button?.
Here is my code.
MyService.java
public class MyService extends Service{
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
//Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
//Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
startApp("com.example.myApp");
Log.d(TAG, "onStart");
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
public void startApp(String packageName){
Calendar c = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
String strDate = sdf.format(c.getTime());
if(strDate == "09:00" || strDate == "15:00" || strDate == "21:00"){
Toast.makeText(this,strDate,Toast.LENGTH_LONG).show();
Toast.makeText(this,"Starting the App",Toast.LENGTH_LONG).show();
Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);
if(intent != null){
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
}
}
MainActivity.Java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//start the service
public void onClickStartServie(View V)
{
//start the service from here
startService(new Intent(this, MyService.class));
}
//Stop the started service
public void onClickStopService(View V)
{
//Stop the running service from here
//Service will only stop if it is already running.
stopService(new Intent(this, MyService.class));
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
I think using alarm manager will be a better option. Set an alarm for that time and receive broadcast in your receiver at that time like below code:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, AppConstants.ALARM_ID_TESTING, new Intent(
AppConstants.FILTER_TESTING), PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + millisAfterCurrent, pendingIntent);
Add receiver in manifest:
<receiver
android:name=“TestReceiver"
<intent-filter>
<action android:name="filter.test.time” />
</intent-filter>
And receiver class as:
class TestReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(AppConstants.FILTER_TESTING))
{
// code here
}
}
}
Why dont you try Time Changed Receiver instead of service, Since using a background service is bad programming approah.A service keeps on running in background and takes a lot of system memory and a burden battery. Moreover system can stop any of extra services running at anytime for adjustment of memory issues.
A time change receiver is the best approach and in that you can compare time and open any app accordingly.
i suggest you this two ways:
Use the "new" ScheduledThreadPoolExecutor as replacement for Timer
Example:
int threadCount = 1;
ScheduledThreadPoolExecutor service = new ScheduledThreadPoolExecutor(threadCount);
long initialDelay = 5;
long period = 10;
ScheduledFuture<?> task = service.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
// DO IT EVERY 10 SECONDS
}
}, initialDelay, period, TimeUnit.SECONDS);
[...]
//if you want you can cancel the task later
task.cancel(true); // mayInterruptIfRunning = true
Since Activities, Threads and Processes can be terminated anytime by Android OS it is not guaranteed that the job is always executed.
Therefore, it is better to use AlarmManager
Official howto: Scheduling Repeating Alarms
Another nice example: Repeat Alarm Example In Android Using AlarmManager

EventListener for Power Button press in a Service

I want to listen the power key event in the service.
How can in do that ?
Currently I am working with an app, where I need to listen the power button for some events, from a service which is running in a background, even when the app is killed or stopped.
Somehow I can manage to get it.
But when I kill/stop the app, the service is getting stopped.
How can i overcome this ?
Currently the code i am using this :
Service Class:
public class SampleService extends Service
{
SettingContentObserver mSettingsContentObserver;
AudioManager mAudioManager;
private ComponentName mRemoteControlResponder;
private Intent intent;
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
Log.v("StartServiceAtBoot", "StartAtBootService -- onStartCommand()");
// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}
#Override
public void onStart(Intent intent, int startId) {
boolean screenOn = intent.getBooleanExtra("screen_state", false);
if (!screenOn) {
Toast.makeText(getApplicationContext(), "On", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Off", Toast.LENGTH_SHORT).show();
}
}
public void onCreate()
{
mSettingsContentObserver = new SettingContentObserver(this,new Handler());
getApplicationContext().getContentResolver().registerContentObserver
(android.provider.Settings.System.CONTENT_URI, true, mSettingsContentObserver );
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mRemoteControlResponder = new ComponentName(getPackageName(),
StartAtBootServiceReceiver.class.getName());
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new StartAtBootServiceReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
public void onDestroy()
{
getApplicationContext().getContentResolver().unregisterContentObserver(mSettingsContentObserver);
}
}
BroadcastReceiver Class:
public class StartAtBootServiceReceiver extends BroadcastReceiver
{
static boolean wasScreenOn;
private boolean screenOff;
public void onReceive(Context context, Intent intent)
{
if(intent.getAction().equals(Intent.ACTION_SCREEN_OFF))
{
wasScreenOn = false;
Toast.makeText(context, "Power Off", Toast.LENGTH_SHORT).show();
}
else if(intent.getAction().equals(Intent.ACTION_SCREEN_ON))
{
wasScreenOn = true;
}
Intent i = new Intent(context, SampleService.class);
i.putExtra("screen_state", screenOff);
i.setAction("com.example.antitheft.SampleService");
context.startService(i);
//
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent i1 = new Intent();
i1.setAction("com.example.sampleonkeylistener.MainActivity");
context.startService(i1);
}
}
}
given above is the sample code and i have created AndroidManifest.xml files also with user's permission but i cannot get the app continue service if it is killed or stopped.
Thanks in Advance.
#Override
public void onDestroy() {
super.onDestroy();
startService(new Intent(this, SampleService.class));
}
This is one way to ensure that service will never stop even user want to destroy it.
This is one Just ONE of ways to achieve what you are trying to achieve.
Secondly, you can try and run service in "foreground" by using startForeground().
Also, make sure that in you return "START_STICKY" (which you are doing in the sample code that you shared and I trust that you are also doing in App's code too :) ) in Services's onStartCommand().
This will ensure that If this service's process is killed while it is started (after returning from onStartCommand(Intent, int, int)), then leave it in the started state but don't retain this delivered intent. Later the system will try to re-create the service.
And you may find some additional pointers/hints to make sure your service is not stopped at below link.
How can we prevent a Service from being killed by OS?
Just pick and choose the approach that best suits YOUR Need/implementation.

Code is fine(?), but app is running slow on Android (service+ intents)

So I've got 3 java files :
ServiceActivity - main activity where everything starts ( static int i is defined earlier in this file)
Elserwis - it is the service (it has a timer where I've passed the variable i -> it will be the hour since when the timer must turn on)
Sekundo - the intent where user puts the hour => >variable i<
Here is the fragment of code from main activity -> ServiceActivity:
private OnClickListener startListener = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(getApplicationContext(), Sekundo.class);
startActivityForResult(intent,1337);
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data ) {
/* Place out code to react on Activity-Result here. */
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1337){
i=data.getIntExtra("result",5);
Toast tost = Toast.makeText(getApplicationContext(), "ELO"+data.getIntExtra("result",0)+data.getIntExtra("result1",0), 1000);
tost.show();
startService(new Intent(SerwisActivity.this,Elserwis.class));
}
}
I think the problem is in the end, where startService lays (as a subfunction of onActivityResult)
If you need any other fragment of code I can paste it here, but the question is:
My app is running very slowly at the beginning when the timer starts, and the Toast shows for over 1 minute. Anyone know why?
EDIT:
public class Elserwis extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
okresowePowiadomienie();
Toast.makeText(getApplicationContext(),"Service LAUNCHED!", 1000).show();
}
Date data33 = new Date(111,11,SerwisActivity.i,2,25);
int d = data33.getDate();
Timer timer = new Timer();
public void okresowePowiadomienie(){
TimerTask timerTask = new TimerTask(){
public void run() {
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher,"OKRes",System.currentTimeMillis());
Intent notIntent = new Intent(getApplicationContext(), SerwisActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),"Powiadomienie x:","Kliknij aby d:usunac ;)t:"+d,contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1335, notification);
// } };
}};
timer.scheduleAtFixedRate(timerTask ,data33 , 120000); }
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
Toast.makeText(this, "Service dead!", Toast.LENGTH_LONG).show();
}
}
thats just alpha version of my code but final will be similar ( now it only passes information about the day to my service -> in final version it should pass hour and minute)
The "Service LAUNCHED!" toast stays on for ages, it crashes most of the time on AVD, on my real smartphone it just takes long but still it should work smoothly...
Basically the problem started when i moved startService from onClick() function TO the onActivityResult. It needs to stay there because service uses the int i (user types types int i in the new intent) to set the data for my timer(timer is in the Elserwis). I've updated my first post with the service code so u can get what i mean
I'm GUESSING that startService itself is not causing any blocking.
I'm GUESSING that you have code in startService that takes awhile to complete and causes your application UI to lock up.
If this is the case, then what you would need to do is create a new thread inside your service before running the code that causes the delay.
You need to keep any long-running blocks of code in a separate thread to not block the UI. I would be interested in the code that is in Elserwis.class because that would help identify where the problem actually lies. Or if you look at your code and figure it out based on what I said, then you need not post any more code.

Categories