When Android Wear goes to sleep mode (screen dimmed), some parts of my code are not executed. I use Timer in background service to trigger some actions, such as sending data from wear to mobile, but the data is not sent. It is sent when I tap the screen to wake it up.
I also try to use Timer trigger a notification with vibration when the screen is off, but it doesn't appear until I tap the screen.
In debug mode (either Bluetooth or USB), data sending and notification work fine.
I suspect this is because when Android Wear is in sleep mode, its CPU works at minimum level because the Timer is still running, but not for GoogleApiClient, IntentService, or Notification.
I have tried many ways to wake CPU up such as AlarmManager, PowerManager, Wakelock, but it did not work for Android Wear.
Anyone has encountered this problem? What is the solution?
I'm using PowerManger to wakeup my wearable device each time i receive message from handled device.
Do not forget to release PowerManager.WakeLock
public abstract class WatchFaceActivity extends Activity {
private PowerManager.WakeLock mWakeLock;
private Handler mWakeLockHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock_watch_face);
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "MyWakelockTag");
mWakeLockHandler = new Handler();
IntentFilter messageFilter = new IntentFilter("message-forwarded-from-data-layer");
MessageReceiver messageReceiver = new MessageReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
}
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
}
mWakeLockHandler.removeCallbacksAndMessages(null);
mWakeLockHandler.postDelayed(mReleaseRunnable, 5000);
}
}
private Runnable mReleaseRunnable = new Runnable() {
#Override
public void run() {
mWakeLock.release();
}
};
#Override
protected void onDestroy() {
super.onDestroy();
mWakeLockHandler.removeCallbacksAndMessages(null);
mWakeLock.release();
}
}
And allow WAKE_UP permission in your Manifest.
<uses-permission android:name="android.permission.WAKE_LOCK" />
You should use AlarmManager along with WakefulBroadcastReceiver and startWakefulService(). See this working solution.
You may find answers for your further questions in chat history on that post here.This is the only solution worked for our app.
#SeaDog is successful in making http calls when device in deep sleep mode with this solution. Try it.
Related
I have an Android Wear watch face that I'm trying to have vibrate the watch on the hour. It is working except in cases where the watch screen is off. According to the log statements, the handler method is called every minute and the chime method is called on the hour. If I'm debugging over bluetooth with the Moto 360, it works even with the screen off. If I install a release apk, it only vibrates if the screen is on. If the screen is off at the top of the hour, it wont vibrate until the screen comes back on. I have tried acquiring a wake lock before the vibrate with no luck. I'm thinking it may work if I acquire a wake lock in the onCreate and release it in the onDestroy but I would rather not do that to preserve battery. Another interesting tidbit is that I have another function that vibrates when certain data changes in the wearable data api and that is working with the screen off. Maybe the WearableListenerService wakes the watch up long enough for the vibrate to occur. Is there something wrong with my logic or is this a limitation of certain Android Wear devices?
Time change handler:
final Handler mUpdateTimeHandler = new Handler() {
#Override
public void handleMessage(Message message) {
switch (message.what) {
case MSG_UPDATE_TIME:
MyLog.d("Time Tick Message Handler");
doTimeTickStuff();
long timeMs = System.currentTimeMillis();
long delayMs = mInteractiveUpdateRateMs - (timeMs % mInteractiveUpdateRateMs);
mUpdateTimeHandler.sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs);
break;
}
}
};
doTimeTickStuff()
private void doTimeTickStuff()
{
MyLog.d("timetickstuff");
try {
mCalendar = Calendar.getInstance();
int currMin = mCalendar.get(Calendar.MINUTE);
if (currMin == 0) {
hourlyChime();
}
}
catch(Exception ex)
{
MyLog.e(ex, "Error occurred in time tick handler");
}
if (mIsVisible) {
invalidate();
}
}
hourlyChime()
private void hourlyChime(){
Vibrator v = (Vibrator) getBaseContext().getSystemService(VIBRATOR_SERVICE);
if (v.hasVibrator()) {
MyLog.d("vibrating");
v.vibrate(1000);
}
else {
MyLog.d("No vibrator");
}
}
Update
The solution that worked was to create an AlarmManager and register it with a broadcast receiver in the watch face onCreate then unregister the receiver in onDestroy
onCreate()
#Override
public void onCreate(SurfaceHolder holder) {
super.onCreate(holder);
mChimeAlarmManager =
(AlarmManager) getSystemService(Context.ALARM_SERVICE);
Intent ambientStateIntent = new Intent("packagename.HOURLY_CHIME");
mChimePendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
1234, ambientStateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
WeatherTime.this.registerReceiver(chimeReceiver,
new IntentFilter("packagename.HOURLY_CHIME"));
long alarmMs = getMsTillNextHour() + System.currentTimeMillis();
mChimeAlarmManager.setExact(
AlarmManager.RTC_WAKEUP,
alarmMs,
mChimePendingIntent);
}
Broadcast Receiver
private BroadcastReceiver chimeReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent) {
hourlyChime();
mChimeAlarmManager.setExact(
AlarmManager.RTC_WAKEUP,
getMsTillNextHour() + System.currentTimeMillis(),
mChimePendingIntent);
}
};
onDestroy()
#Override
public void onDestroy() {
mChimeAlarmManager.cancel(mChimePendingIntent);
super.onDestroy();
}
When the watch goes into ambient mode, it goes into a deep sleep. As a result, code written with Handler will not run. As a result, you should use AlarmManager. For details on how to implement this, you should refer to the "Update more frequently" section on this page about the always-on functionality of Android Wear.
With regards to Bluetooth debug mode, I suspect that it works because the watch never goes into deep sleep. The same happens when I develop apps while the watch is docked.
Lastly, as for the wake up frequency, I think your functionality is fine as it only fires once an hour. For others reading this, please refrain from waking the watch up more than once a minute as this will severely impact battery life. Always test your watch face for battery life before uploading to the Play Store.
in my project i use Alarm manager with MyIntentService extends IntentService.
To wake up (on screen) device in onHandleIntent
use following:
if (intent.getAction() != null) {
tmp = intent.getAction();
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), TAG);
wakeLock.setReferenceCounted(true);
if(!wakeLock.isHeld()) {
wakeLock.acquire();
}
}
I made an application with: an activity (MainActivity) that starts a service (SmartphoneListener).
Activity
public class MainActivity extends Activity implements GoogleApiClient.ConnectionCallbacks{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this,SmartphoneListener.class);
startService(intent);
}
}
The service is used to detect (on smartphone) if the connection with smartwatch is lost.
Service
public class SmartphoneListener extends WearableListenerService {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"MyWakelockTag"); //Service running even if the screen is off.
wakeLock.acquire();
return START_STICKY;
}
#Override
public void onPeerDisconnected(Node node){
Toast.makeText(getApplicationContext(),"Communication with smartwatch lost",Toast.LENGTH_SHORT).show();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
registerReceiver(mIntentReceiver, filter);
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver(){
public void onReceive(Context context, Intent intent) {
//
}
};
...
}
If my application is open and the smartphone screen is off I can detect if I lost my connection with smartwatch (the mIntentReceiver code is executed).
Then If I close my application and the smartphone screen is off I can't detect if I lost my connection with smartwatch (the mIntentReceiver code is not executed).
I don't know why.
Try to add
filter.addAction(Intent.ACTION_SCREEN_OFF);
to your IntentFilter. Hope it help!
You explained in the reply to my comment that you are "closing" the app by swiping it from the recent tasks list. This action causes the process for your app to be killed. Because you return START_STICKY from onStartCommand() in your service, the system will create a new instance of your app in a new process and call onStartCommand() to restart your service. That is the only entry made into your app. No activities are recreated. I know very little about Wear. I'm guessing that your app performs some configuration processing to locate and connect to nodes. If that processing is done in some activity, such as your launch activity, it will not be performed when your app is recreated to restart your service.
I need to force the android device to stay alive while the application is running. There any way to do this ?
I read here : Is there a way to force an android device to stay awake? about this, I tried to do this but probably I don't know to use correctly a Service.
This is the code I use :
public class WakeLockService extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "My Tag");
wl.acquire();
}
#Override
public void onDestroy() {
wl.release();
}
and in the first Activity of my Application, I put this :
Intent s = new Intent(this, WakeLockService.class);
startService(s);
Is it correct what I'm doing? Anyone can help me to do this ?
Thanks in advance.
If you want the device to stay awake while it displays an activity of your app, you have to set the flag FLAG_KEEP_SCREEN_ON when creating the activity:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); // Unlock the device if locked
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); // Turn screen on if off
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // Keep screen on
.....
}
Add the permission WAKE_LOCK in the manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
EDIT After seeing your last comment: yes, you need a service: note that the device will go to sleep anyway, but your service can continue to run if you make it clear to the user (you have to display a notification) and declare it STICKY:
public class yourservice extends Service
{
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//The intent to launch when the user clicks the expanded notification
/////////////////////////////////////////////////////////////////////
Intent forPendingIntent = new Intent(this, si.test.app.activities.activity.class);
forPendingIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendIntent = PendingIntent.getActivity(this, 0, forPendingIntent, 0);
Notification notification = new Notification(R.drawable.icon, "testapp", System.currentTimeMillis());
notification.setLatestEventInfo(this, "testApp", "testApp is running", pendIntent);
notification.flags |= Notification.FLAG_NO_CLEAR;
startForeground (R.string.app_name, notification);
return START_STICKY;
}
...
}
In my application I have, for example, a syncronization server->mobile and this syncronization can run more then 5 minutes. I want to force the device to not enter into stand-by, to see when the syncronization process is finished
The synchronization operation should be managed by some Android component, such as a service. That component can manage a WakeLock. Do not create some separate component purely for the WakeLock, as that other component has nothing whatsoever to do with your synchronization work.
For example, if your synchronization is being conducted via an IntentService, you could use my WakefulIntentService to keep the device awake while the work in onHandleIntent() is being conducted.
I am trying to figure out how to wake and unlock the phone with a service. I have been referring to this post but, I can't figure out why it isn't working. This is the code that I have so far:
public class WakephoneActivity extends Activity {
BroadcastReceiver mReceiver;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Log.v(TAG, "Screen OFF onReceive()");
screenOFFHandler.sendEmptyMessageDelayed(0, 2000);
}
};
}
private Handler screenOFFHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// do something
// wake up phone
// Log.i(TAG, "ake up the phone and disable keyguard");
PowerManager powerManager = (PowerManager) WakephoneActivity.this
.getSystemService(Context.POWER_SERVICE);
long l = SystemClock.uptimeMillis();
powerManager.userActivity(l, false);// false will bring the screen
// back as bright as it was, true - will dim it
}
};
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(mReceiver, filter);
// Log.i(TAG, "broadcast receiver registered!");
}
}
I have added the code in the manifest as well. Any ideas?
Use this code below in your service.
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie");
mWakeLock.acquire();
[...]
mWakeLock.release();
If you want to unlock the screen as well, register a receiver in your service that monitors if the screen is turned on/off and if it is turned off and you want to unlock the phone, start an activity with this code in onCreate:
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
this.finish();
return;
I know, this is a rather dirty, but as far as I know, there is no other way of unlocking the lockscreen (and this will only work if there are no passwords etc set, so it must be the normal "slide to unlock" screen).
And don't forget to add android.permission.WAKE_LOCK ;-)
/edit: I just saw you are already using an Activity. If you have one and don't need the service at all, just put this code into the activity.
For the service to be allways active you need to have this permission on manifest:
<uses-permission android:name="android.permission.WAKE_LOCK" />
Another thing you need to do is to adquire a WakeLock. Without it the service will end passed some time. You can do it like this:
getApplicationContext();
PowerManager pm = (PowerManager)getApplicationContext().getSystemService(Context.POWER_SERVICE);
WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
wl.acquire();
You might need to change PowerManager.PARTIAL_WAKE_LOCK to the one that you need. You can see info about that here.
There is WakefulBroadcastReceiver which does this for you. Example use:
import android.content.Context;
import android.content.Intent;
import android.os.SystemClock;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Log;
public class SimpleWakefulReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// This is the Intent to deliver to our service.
Intent service = new Intent(context, SimpleWakefulService.class);
// Start the service, keeping the device awake while it is launching.
Log.i("SimpleWakefulReceiver", "Starting service # " + SystemClock.elapsedRealtime());
startWakefulService(context, service);
}
}
After completing the action in the service, call SimpleWakefulReceiver.completeWakefulIntent(intent) to release the wake lock.
(as #Force already gave you the details about the wakeLock, they need not be repeated here ;-)
Mind that the class is deprecated from api level 26.1.0, reference here
im receiving an intent in broadcast receiver and then i start service to do more work. now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
does my service will stop running if the device goes to sleep without getting a wakelock.
now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
If the device is asleep to begin with, you will not be "receiving an intent in broadcast receiver", because the device is asleep.
do i have to get Wakelock (AlarmManger?), and why do i need it?
You don't "need it", unless you want to ensure the device stays running while you complete some work.
does my service will stop running if the device goes to sleep without getting a wakelock.
Yes.
Looks like the Android's native WakefulBroadcastReceiver would be a perfect solution for you. Need to extend this rather than the regular BroadcastReceiver and start the service in the onReceive() in the "wakeful" manner:
startWakefulService(context, service);
and signal your work is done in the service's onHandleIntent(), calling
MyWakefulReceiver.completeWakefulIntent(intent);
public class WakeLockManager extends BroadcastReceiver {
private static WakeLock mWakeLock;
private String LCLT;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Consts.WAKELOCK_INTENT)) {
Log.v("wakelock", "GOT THE wakelock INTENT");
boolean on = intent.getExtras().getBoolean("on");
if (mWakeLock == null) {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"Breeze WakeLock");
}
if (on) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
Log.v("wakelock", "acquiring wakelock");
}
} else {
if (mWakeLock.isHeld()) {
Log.v("wakelock", "releasing wakelock");
mWakeLock.release();
}
mWakeLock = null;
}
}
}
}
look at the above code ..put it in a separate class file and and in your manifest define it for some custom intent .... now that this class will respond to a custom intent ...just broadcast that intent and you can turn the wakelock on or off in your entire app since the wakelock is static..like this :
public void setWakeup(boolean status) {
Intent wakelock_Intent = new Intent(CUSTOM_INTENT);
wakelock_Intent.putExtra("on", status);
this.sendBroadcast(wakelock_Intent);
}
the above would be defined in your alarmmanager code so it schedules a call