Android: Overriding the power button in a Fragment - android

I'm working on a thing where I need to override the power button in a Fragment when pressed. I did this successfully, however, the screen turns off when the power button is pressed.
I did a quick search and came across a few posts like this, this, and this. Some say it's doable and others say it's not. My question is that is this even doable? If so, any idea how to go about this?

You can use this to prevent screen from locking
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
While using in fragment
getActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
Use a BroadcastReceiver and listen for the android.intent.action.SCREEN_OFF or Intent.ACTION_SCREEN_OFF which is sent when power button is pressed (and screen is on). What i think is that overriding the power button is not possible , because of security issues.

What you are doing is not advisable. However you can write a broadcast receiver and then the screen gets locked, wake it up using AlarmManager. Below is the code.
#Override
public void onReceive(Context context, Intent intent) {
if ((intent.getAction().equals(Intent.ACTION_SCREEN_OFF))) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "TEST");
wakeLock.acquire();
AlarmManager alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent inten = new Intent(context,NewActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 0, inten, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 100, pi);
}
}
// Finish your WakeLock HERE. call this method after U put the activity in front or when u exit from the new activity.
public void finishWakeLocker(){
if (wakeLock != null)
wakeLock.release();
}

You cannot override the power button functionality however you can prevent system from showing dialog on long press of a power button using following.
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!hasFocus) {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}

Related

startActivity for URI in Lockscreen on Android Nougat

I'm using a BroadcastReceiver that receives a broadcast from an AlarmManager. In the receiver I am starting two activities. One activity is started from a URI like this and is a third-party app:
// Open spotify
Intent spotify = new Intent(Intent.ACTION_VIEW, Uri.parse(song));
spotify.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
context.startActivity(spotify);
} catch (ActivityNotFoundException e) {
status = Status.SPOTIFY_NOT_INSTALLED;
}
After that I start another activity that belongs to the app with a 5 second delay using the AlarmManager again:
public static void setExact(
Context context, PendingIntent pendingIntent, long time
) {
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
am.setExact(AlarmManager.RTC_WAKEUP, time, pendingIntent);
else
am.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
}
public static void setExactDelay(
Context context, PendingIntent pendingIntent, long delay
) {
setExact(context, pendingIntent, System.currentTimeMillis() + delay);
}
PendingIntent pendingIntent = AlarmPlayActivity.makePendingIntent(context, alarm, status, startTime);
AlarmSet.setExactDelay(context, pendingIntent, 5000);
The second activity starts in 5 seconds as expected. However the first activity only starts when the device is unlocked. If the device is locked it does not start on Android Nougat (7.0). This is the case even when the lock is not secured by password, pattern etc. This used to work on earlier Android versions, even with a secure lock.
Is there a method by which I can start the first activity without needing the screen to be on?
Edit: I've tried using the following IntentService. It works when the device is awake and unlocked but there is no luck when the device is locked:
public class AlarmService extends IntentService {
static final int NOTIFICATION_ID = 1;
public AlarmService() {
super("AlarmService");
}
public static Intent makeIntent(Context context, Alarm alarm, AlarmReceiver.Status status, long startTime) {
Intent intent = IntentFactory.alarmPlayIntent(alarm, status, startTime);
intent.setClass(context, AlarmService.class);
return intent;
}
private static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
// Nothing
}
}
#Override
protected void onHandleIntent(Intent intent) {
// Acquire Wakelock immediately
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = pm.newWakeLock(
PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE,
"AlarmServiceWakeLock"
);
wakeLock.acquire();
KeyguardManager.KeyguardLock lock = ((KeyguardManager) getSystemService(Activity.KEYGUARD_SERVICE)).newKeyguardLock(KEYGUARD_SERVICE);
lock.disableKeyguard();
// Get intent data
final Alarm alarm = IntentFactory.getAlarm(intent);
AlarmReceiver.Status status = IntentFactory.getStatus(intent);
final long startTime = IntentFactory.getStartTime(intent, 0);
// Get a random song for this alarm
AlarmDatabase db = AlarmDatabase.getInstance(this);
Song song = db.getRandomSong(alarm);
String songName = song == null ? "backup sound" : song.getName();
// Start a foreground notification
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(getText(R.string.alarm_starting_notification_title))
.setContentText(getString(
R.string.alarm_starting_notification_message, alarm.getName(), songName
))
.setSmallIcon(R.drawable.ic_launcher)
.setPriority(NotificationCompat.PRIORITY_MAX)
.build();
startForeground(NOTIFICATION_ID, notification);
// Potentially open Spotify if we can
if (song != null) {
// Open spotify
Intent spotify = new Intent(Intent.ACTION_VIEW, Uri.parse(song.getUri()));
spotify.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
try {
startActivity(spotify);
} catch (ActivityNotFoundException e) {
status = AlarmReceiver.Status.SPOTIFY_NOT_INSTALLED;
}
} else
status = AlarmReceiver.Status.NO_SONGS;
// Start play activity in 10 seconds, giving Spotify some chance to load up.
sleep(10);
startActivity(AlarmPlayActivity.makeIntent(this, alarm, status, startTime));
// Keep alive for 5 more seconds
sleep(5);
// Stop notification
stopForeground(true);
// Release wakelock
wakeLock.release();
}
}
I experienced the same issue and i think Intent.ACTION_VIEW don't work until you unlock the screen because of safety reasons.
Same issue discussed here also. You can also check this link
You have to use up-to-date methods:
either
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nexttime, pendingintent);
or
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nexttime, pendingintent);
Do not forget to set your i awake mode:
to start:
PowerManager pm = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE, A_.APPNAME + Integer.toString(index));
if (wakeLock != null && wakeLock.isHeld()){
wakeLock.acquire();
}
to release:
wakeLock.release();
you can set your activity as foreground (over lock screen)
described here:
https://stackoverflow.com/a/23611199/1979882
import android.view.Window;
import android.view.WindowManager.LayoutParams;
Window window = this.getWindow();
window.addFlags(LayoutParams.FLAG_DISMISS_KEYGUARD);
window.addFlags(LayoutParams.FLAG_SHOW_WHEN_LOCKED);
window.addFlags(LayoutParams.FLAG_TURN_SCREEN_ON);
You can start your activity as shown here too:
https://stackoverflow.com/a/6468575/1979882
#Override
public void onReceive(Context context, Intent intent) {
//start activity
Intent i = new Intent();
i.setClassName("com.test", "com.test.MainActivity");
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
Instead of starting your Spotify activity directly from the receiver, have the receiver instead start a Service from your own app.
Inside of the service, acquire your wakelock and then start a Foreground notification (build notification with NotificationCompat.Builder then use startForeground(mId, notification);, this notification will keep the service alive in cases where Nougat would otherwise stop it.
Then fire your Spotify Intent from the service, afterwards of course kill the service, foreground notification, and wakelock. This has worked for me before to avoid pesky Nougat problems like you are facing. Hope this helps!
In my case, the second activity also could not open without wake your phone up.
Solution:
Start activity when screen is off
Bring app to front, turn on display and unlock from AlarmManager?

Android power button override and disable while application runing

hi i need to keep the device screen on mood, while application running.
disable the power button functionality to off the screen.
I have tried following codes
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
and wake locks
#Override
public void onReceive(Context context, Intent intent) {
if ((intent.getAction().equals(Intent.ACTION_SCREEN_OFF))) {
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, "TEST");
wakeLock.acquire();
AlarmManager alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
Intent inten = new Intent(context,NewActivity.class);
PendingIntent pi = PendingIntent.getActivity(context, 0, inten, 0);
alarmMgr.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, 100, pi);
}
}
// Finish your WakeLock HERE. call this method after U put the activity in front or when u exit from the new activity.
public void finishWakeLocker(){
if (wakeLock != null)
wakeLock.release();
}
Thanks in advance
This is not possible, for security reasons. HOME and POWER buttons are two things you will not be able to directly override without system-grade permissions. After all, the user wouldn't like your app to take control of their device, would they? ;-)
You should plan the functionality in such a way that a wakelock or
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
is enough :-)
EDIT:
There are tutorials such as the one uday linked, but the effects are generally unreliable and work only on some devices. I have developed an app like that and trust me, you do not want to have to debug this ;-)

Wake up app from sleep at set time

I want to send my app to sleep and then wake it up at set times. I have it going to sleep but not waking up.
This sets the wakelock:
private void setWakeLock(){
System.out.println("wakelock");
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, "DoNotDimScreen");
wl.acquire();
}
This sets alarms for wake/sleep times:
private void setWakeSleep(){
java.util.Calendar c = java.util.Calendar.getInstance();
c.set(java.util.Calendar.HOUR_OF_DAY, 17);
c.set(java.util.Calendar.MINUTE, 53);
c.set(java.util.Calendar.MILLISECOND, 0);
Intent sleepIntent = new Intent("SLEEP_INTENT");
PendingIntent sleepPendingIntent = PendingIntent.getBroadcast(this, 0, sleepIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), sleepPendingIntent);
c.set(java.util.Calendar.HOUR_OF_DAY, 18);
c.set(java.util.Calendar.MINUTE, 14);
c.set(java.util.Calendar.MILLISECOND, 0);
Intent wakeIntent = new Intent("WAKE_INTENT");
PendingIntent wakePendingIntent = PendingIntent.getBroadcast(this, 0, wakeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager2 = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager2.set(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), wakePendingIntent);
}
And this is the broadcast receiver:
private BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Time updateHour = new Time();
updateHour.set(System.currentTimeMillis());
if (intent.getAction().equals("SLEEP_INTENT")) {
System.out.println("sleep");
wl.release();
}
if (intent.getAction().equals("WAKE_INTENT")) {
wl.acquire();
System.out.println("wake");
//initialise();
}
}
};
Any help greatly appreciated!
First, you don't want a wakelock; those are for keeping the device from going to sleep, which is highly anti-social unless your app really requires it (it kills the battery).
Second, your code to set the wakeup time will fail if you call it after 18:14 since you'll now be defining a time in the past. Let's ignore that for now.
Next, your intent action should be something like "org.user1797190.WAKE_INTENT" rather than simply "WAKE_INTENT" which could cause collisions. If you anticipate making this intent public, consider registering it at http://openintents.org. That's not your problem either, though.
You don't need alarmManager2 -- there's only one alarm manager in the system, so just re-use the first one.
I've never heard of making an app go to "sleep" per se. Do you mean you want the app to go away, and then come back later?
Here is what I would do. Forget about the "SLEEP_INTENT" completely. Just schedule a "WAKE_INTENT" and then call finish(). Your app will simply leave the screen.
I would forget about the broadcast receiver entirely. Instead, I would use getActivity() instead of getBroadcast() to get a pending intent that will restart the activity. Modify your manifest so that your WAKE_INTENT will go to the activity. Also, you should set the "android:launchMode" property to "singleTask" so multiple instances of your activity aren't created. You'll also need to implement onNewIntent() to handle the wakeup intent if your activity is already running when it arrives.
Finally, if your activity is part of the same application that will be creating the intent, you don't need a named intent at all; you can create them by class. You'll need another way to let the receiver know that this is a wakeup intent though.
So, putting it all together:
Your manifest should contain:
<activity android:name=".TestActivity" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Your code should contain:
/**
* Arrange for the activity to return at a specific time.
* Call finish() after calling this method().
* This function can be called from anywhere that has a valid Context.
*/
public static void scheduleWakeup(Context ctx, long timeMillis) {
if (DEBUG) Log.d(TAG, "Scheduling wakeup for " + timeMillis);
Intent intent = new Intent(ctx, TestActivity.class);
intent.putExtra("wakeup", true);
PendingIntent pi = PendingIntent.getActivity(ctx, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager mgr = (AlarmManager) ctx.getSystemService(Context.ALARM_SERVICE);
mgr.cancel(pi); // Cancel any previously-scheduled wakeups
mgr.set(AlarmManager.RTC_WAKEUP, timeMillis, pi);
}
...
protected void onCreate(Bundle state) {
Intent intent = getIntent();
if (intent.getBooleanExtra("wakeup", false)) {
// We were woken up by the alarm manager
}
...
}
protected void onNewIntent(Intent intent) {
if (intent.getBooleanExtra("wakeup", false)) {
// We were woken up by the alarm manager, but were already running
}
}
This is pretty close to what I'm doing in my own apps, and it works pretty well for me.
You'll have to test this yourself, of course. Log.d() is your friend.
as above. The problem was that I was using a broadcast receiver within the calling activity.

How to force an android device to stay alive while the application is running

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.

Service pauses on screen lock

For testing purposes i have made a service that beeps
every 1 minute. (No client-server interface yet). It beeps okay when
the screen in on, but when it goes to sleep the beeping stops.
I am making an application that has to periodically poll the a server
for something.
For this, I am trying to create a service that'll constantly be
running in the background, poll the server every 1 min and then based
on the reply from server it shall generate a task bar notification.
I have a test activity with two buttons, 1 to start and the other to
stop the service. And one service class named S_PS_PollService
The setOnClickListener of 'Start Activity' button contains:
Thread pollServiceThread = new Thread() {
public void run() {
startService(new Intent(MM_MainMenu.this,
S_PS_PollService.class));
}
};
pollServiceThread.start();
The 'Stop Activity' button simply has:
stopService(new Intent(MM_MainMenu.this, S_PS_PollService.class));
Following are the methods from S_PS_PollService class:
public void onCreate() {
pollSound = MediaPlayer.create(this, R.raw.chirp);
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent myIntent = new Intent(this, S_PS_PollService.class);
pendingIntent = PendingIntent.getService(this, 0, myIntent, 0);
// for wake lock
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag")
// for calendar
calendar = Calendar.getInstance();
}
Onstart:
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
wl.acquire();
pollSound.start();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MILLISECOND, 60000);
alarmManager.set(AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(), pendingIntent);
wl.release();
}
Whenever the alarm kicks off onStart() method is executed, making the
beep and setting new alarm. But it works only as long as screen is on.
I have tried for https://github.com/commonsguy/cwac-wakeful but didnt
get it. Relatively new to android ...
Please help me, im very desperate :) Thanks, !
You have to use the AlarmManager, there are plenty of posts here on stackoverflow.
You want to acquire a partial wake lock (leaving the CPU running whenever sleep is entered on the device) as suggested by your code.
The issue is your presumably overriden on start releases the wake lock. You want to release your wakeLock in onDestroy .. once your service is finished running.
This finally worked for me.
Download the CWAC-WakefulIntentService.jar from https://github.com/commonsguy/cwac-wakeful
add a class in your project
import com.commonsware.cwac.wakeful.WakefulIntentService;
public class WakeService extends WakefulIntentService {
public WakeService(String name) {
super(name);
}
#Override
protected void doWakefulWork(Intent intent) {
}
}
now add the following line in your code where ever you want to repeat the loop and wake the device up
WakefulIntentService.sendWakefulWork(this, S_WS_WakeService.class);

Categories

Resources