On an Android device, where the only buttons are the volume buttons and a power button, I want to make the app react to presses on the power button (long and short). How is this done?
The existing answers don't completely answer the question and leave out enough details that they won't work without more investigation. I'll share what I've learned solving this.
First you need to add the following permission to your manifest file:
<uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
To handle short and long presses add the following overrides to your activity class:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
event.startTracking(); // Needed to track long presses
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
return true;
}
return super.onKeyLongPress(keyCode, event);
}
Note: It is worth noting that onKeyDown() will fire multiple times before onKeyLongPress does so you may want to trigger on onKeyUp() instead or other logic to prevent acting upon a series of onKeyDown() calls when the user is really holding it down.
I think this next part is for Cyanogenmod only. If the PREVENT_POWER_KEY constant is undefined then you should not need it.
To start intercepting the power key you need to set the following flag from your activity:
getWindow().addFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
To stop intercepting the power key (allowing standard functionality):
getWindow().clearFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
You can switch back and forth between the two modes repeatedly in your program if you wish.
Solution:
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Intent i = new Intent(this, ActivitySetupMenu.class);
startActivity(i);
return true;
}
return super.dispatchKeyEvent(event);
}
On you activity add:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
// do what you want with the power button
return true;
}
return super.onKeyDown(keyCode, event);
}
Though... this kind of keys are somehow special... not sure if it can give problems to you.
As mentioned here https://stackoverflow.com/a/15828592/1065357
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!hasFocus) {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}
Sharing a method to listen for Power button long press. Works with API 23+ permissions:
Asking for system permission to draw overlay (This is not a normal or vulnerable permission). This is not a user permission, so You should really know, what you are doing, by asking for it.
public class MainActivity extends AppCompatActivity {
public final static int REQUEST_CODE = 10101;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkDrawOverlayPermission()) {
startService(new Intent(this, PowerButtonService.class));
}
}
public boolean checkDrawOverlayPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (!Settings.canDrawOverlays(this)) {
/** if not construct intent to request permission */
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
/** request permission via start activity for result */
startActivityForResult(intent, REQUEST_CODE);
return false;
} else {
return true;
}
}
#Override
#TargetApi(Build.VERSION_CODES.M)
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
startService(new Intent(this, PowerButtonService.class));
}
}
}
}
Starting a service and adds a special view to WindowManager
Waiting for an action inside View's onCloseSystemDialogs method.
public class PowerButtonService extends Service {
public PowerButtonService() {
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
//home or recent button
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
Log.i("Key", "Long press on power button");
} else if ("homekey".equals(reason)) {
//home key pressed
} else if ("recentapss".equals(reason)) {
// recent apps button clicked
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
|| event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
|| event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Key", "keycode " + event.getKeyCode());
}
return super.dispatchKeyEvent(event);
}
};
mLinear.setFocusable(true);
View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="powerbuttonpress">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
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=".PowerButtonService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>
service_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
Use Broadcast receiver for power button (Screen On/Off)event
here is solution: create broadcast receiver class
public class CallBroadCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//The screen off position
Toast.makeText(context,"Screen is off",Toast.LENGTH_LONG).show();
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//The screen on position
Toast.makeText(context,"Screen is on",Toast.LENGTH_LONG).show();
}
}}
then follow below steps:
1. Initialize receiver in activity
CallBroadCastReciever broadcastReceiver = new CallBroadCastReciever();
2.Declare receiver in manifest file in tag
<receiver android:name="com.android.CallBroadCastReciever">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
3.For send action and data from activity to receiver put below code in onCreate() or onStrat() method
IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
if (broadcastReceiver != null) {
registerReceiver(broadcastReceiver, intentFilter);
}}
4.Don't forget to unregister receiver in onDestory() method
protected void onDestroy() {
super.onDestroy();
if (broadcastReceiver != null) {
unregisterReceiver(broadcastReceiver);
} }
You could overwrite the public boolean onKeyDown(int keyCode, KeyEvent event) and public boolean onKeyUp(int keyCode, KeyEvent event) functions in your Activity class and test if keyCode is equal to KeyEvent.KEYCODE_POWER.
I haven't tested this, but I would assume the system treats this like it does the Home key in that you cannot stop the system from receiving the key event, you can only observe that it occurs. To test this, try returning True from the above functions and see if this catches the key event.
For all android versions use this code.
I tried R. Zagórski's answer, but I am not able to run this code on Pie. However, I have updated their code in my answer.
PowerButtonService:
public class PowerButtonService extends Service {
public PowerButtonService() {
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
//home or recent button
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
Log.i("Key", "Long press on power button");
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + "0000000000"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
startActivity(intent);
} else if ("homekey".equals(reason)) {
//home key pressed
} else if ("recentapss".equals(reason)) {
// recent apps button clicked
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
|| event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
|| event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Key", "keycode " + event.getKeyCode());
}
return super.dispatchKeyEvent(event);
}
};
mLinear.setFocusable(true);
**// here I done with EDIT**
int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and service_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:layout_height="match_parent">
</LinearLayout>
you have to use this:
BroadcastReceiver screenoff = new BroadcastReceiver() {
public static final String Screenoff = "android.intent.action.SCREEN_OFF";
#Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(Screenoff)) return;
//put code to handle power press here
return;
}};
Related
I am trying capture power click in my android app, I was looking for any solution and I just find one with good results, It is when I detect screenOn/screenOff like this:
public class Receiver extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
}
Intent i = new Intent(context, PowerButtonService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
}
}
The problem in this method is that in my app I am looking for do it with screen Off, then it is not util for me.
I tryed this code also in my MainActivity but this doesn't work, debuging it, this the execution go inside when I push vol up or down but not when I push power key:
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Main", "Dispath event power");
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
Log.d("DISPATCH", "boton pulsado");
return true;
}
return super.dispatchKeyEvent(event);
}
I have the same problem in this one:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
Log.w("Test", "Power button down detected");
return true;
}
return false;
}
Could someone help me? thanks
Edit: I want to catch short key press
Sorry for my english
I want to track volume key down when screen was off. How can I put my code in on receive method?
I want to turn on flashlight when user pressed volume down key and when screen goes off.
MyReceiver.java :
public class MyReceiver extends BroadcastReceiver {
private boolean screenOff;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenOff = true;
// Log.i("via Receiver","Normal ScreenOFF" );
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenOff = false;
} else if(intent.getAction().equals(Intent.ACTION_ANSWER)) {
}
Intent i = new Intent(context, UpdateService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
}
}
You don't need to set event listener inside onReceive(). Try like this
setOnKeyListener(new View.OnKeyListener() {
#Override public boolean onKey(View v, int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
if (screenOff) {
// turn on torch
return true;
}
}
return false;
}
On an Android device, where the only buttons are the volume buttons and a power button, I want to make the app react to presses on the power button (long and short). How is this done?
The existing answers don't completely answer the question and leave out enough details that they won't work without more investigation. I'll share what I've learned solving this.
First you need to add the following permission to your manifest file:
<uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
To handle short and long presses add the following overrides to your activity class:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
event.startTracking(); // Needed to track long presses
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
return true;
}
return super.onKeyLongPress(keyCode, event);
}
Note: It is worth noting that onKeyDown() will fire multiple times before onKeyLongPress does so you may want to trigger on onKeyUp() instead or other logic to prevent acting upon a series of onKeyDown() calls when the user is really holding it down.
I think this next part is for Cyanogenmod only. If the PREVENT_POWER_KEY constant is undefined then you should not need it.
To start intercepting the power key you need to set the following flag from your activity:
getWindow().addFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
To stop intercepting the power key (allowing standard functionality):
getWindow().clearFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
You can switch back and forth between the two modes repeatedly in your program if you wish.
Solution:
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Intent i = new Intent(this, ActivitySetupMenu.class);
startActivity(i);
return true;
}
return super.dispatchKeyEvent(event);
}
On you activity add:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
// do what you want with the power button
return true;
}
return super.onKeyDown(keyCode, event);
}
Though... this kind of keys are somehow special... not sure if it can give problems to you.
As mentioned here https://stackoverflow.com/a/15828592/1065357
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!hasFocus) {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}
Sharing a method to listen for Power button long press. Works with API 23+ permissions:
Asking for system permission to draw overlay (This is not a normal or vulnerable permission). This is not a user permission, so You should really know, what you are doing, by asking for it.
public class MainActivity extends AppCompatActivity {
public final static int REQUEST_CODE = 10101;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkDrawOverlayPermission()) {
startService(new Intent(this, PowerButtonService.class));
}
}
public boolean checkDrawOverlayPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (!Settings.canDrawOverlays(this)) {
/** if not construct intent to request permission */
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
/** request permission via start activity for result */
startActivityForResult(intent, REQUEST_CODE);
return false;
} else {
return true;
}
}
#Override
#TargetApi(Build.VERSION_CODES.M)
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
startService(new Intent(this, PowerButtonService.class));
}
}
}
}
Starting a service and adds a special view to WindowManager
Waiting for an action inside View's onCloseSystemDialogs method.
public class PowerButtonService extends Service {
public PowerButtonService() {
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
//home or recent button
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
Log.i("Key", "Long press on power button");
} else if ("homekey".equals(reason)) {
//home key pressed
} else if ("recentapss".equals(reason)) {
// recent apps button clicked
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
|| event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
|| event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Key", "keycode " + event.getKeyCode());
}
return super.dispatchKeyEvent(event);
}
};
mLinear.setFocusable(true);
View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="powerbuttonpress">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
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=".PowerButtonService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>
service_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
Use Broadcast receiver for power button (Screen On/Off)event
here is solution: create broadcast receiver class
public class CallBroadCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//The screen off position
Toast.makeText(context,"Screen is off",Toast.LENGTH_LONG).show();
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//The screen on position
Toast.makeText(context,"Screen is on",Toast.LENGTH_LONG).show();
}
}}
then follow below steps:
1. Initialize receiver in activity
CallBroadCastReciever broadcastReceiver = new CallBroadCastReciever();
2.Declare receiver in manifest file in tag
<receiver android:name="com.android.CallBroadCastReciever">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
3.For send action and data from activity to receiver put below code in onCreate() or onStrat() method
IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
if (broadcastReceiver != null) {
registerReceiver(broadcastReceiver, intentFilter);
}}
4.Don't forget to unregister receiver in onDestory() method
protected void onDestroy() {
super.onDestroy();
if (broadcastReceiver != null) {
unregisterReceiver(broadcastReceiver);
} }
You could overwrite the public boolean onKeyDown(int keyCode, KeyEvent event) and public boolean onKeyUp(int keyCode, KeyEvent event) functions in your Activity class and test if keyCode is equal to KeyEvent.KEYCODE_POWER.
I haven't tested this, but I would assume the system treats this like it does the Home key in that you cannot stop the system from receiving the key event, you can only observe that it occurs. To test this, try returning True from the above functions and see if this catches the key event.
For all android versions use this code.
I tried R. Zagórski's answer, but I am not able to run this code on Pie. However, I have updated their code in my answer.
PowerButtonService:
public class PowerButtonService extends Service {
public PowerButtonService() {
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
//home or recent button
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
Log.i("Key", "Long press on power button");
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + "0000000000"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
startActivity(intent);
} else if ("homekey".equals(reason)) {
//home key pressed
} else if ("recentapss".equals(reason)) {
// recent apps button clicked
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
|| event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
|| event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Key", "keycode " + event.getKeyCode());
}
return super.dispatchKeyEvent(event);
}
};
mLinear.setFocusable(true);
**// here I done with EDIT**
int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and service_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:layout_height="match_parent">
</LinearLayout>
you have to use this:
BroadcastReceiver screenoff = new BroadcastReceiver() {
public static final String Screenoff = "android.intent.action.SCREEN_OFF";
#Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(Screenoff)) return;
//put code to handle power press here
return;
}};
On an Android device, where the only buttons are the volume buttons and a power button, I want to make the app react to presses on the power button (long and short). How is this done?
The existing answers don't completely answer the question and leave out enough details that they won't work without more investigation. I'll share what I've learned solving this.
First you need to add the following permission to your manifest file:
<uses-permission android:name="android.permission.PREVENT_POWER_KEY" />
To handle short and long presses add the following overrides to your activity class:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
event.startTracking(); // Needed to track long presses
return true;
}
return super.onKeyDown(keyCode, event);
}
#Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
// Do something here...
return true;
}
return super.onKeyLongPress(keyCode, event);
}
Note: It is worth noting that onKeyDown() will fire multiple times before onKeyLongPress does so you may want to trigger on onKeyUp() instead or other logic to prevent acting upon a series of onKeyDown() calls when the user is really holding it down.
I think this next part is for Cyanogenmod only. If the PREVENT_POWER_KEY constant is undefined then you should not need it.
To start intercepting the power key you need to set the following flag from your activity:
getWindow().addFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
To stop intercepting the power key (allowing standard functionality):
getWindow().clearFlags(WindowManager.LayoutParams.PREVENT_POWER_KEY);
You can switch back and forth between the two modes repeatedly in your program if you wish.
Solution:
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Intent i = new Intent(this, ActivitySetupMenu.class);
startActivity(i);
return true;
}
return super.dispatchKeyEvent(event);
}
On you activity add:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
// do what you want with the power button
return true;
}
return super.onKeyDown(keyCode, event);
}
Though... this kind of keys are somehow special... not sure if it can give problems to you.
As mentioned here https://stackoverflow.com/a/15828592/1065357
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!hasFocus) {
Intent closeDialog = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
sendBroadcast(closeDialog);
}
}
Sharing a method to listen for Power button long press. Works with API 23+ permissions:
Asking for system permission to draw overlay (This is not a normal or vulnerable permission). This is not a user permission, so You should really know, what you are doing, by asking for it.
public class MainActivity extends AppCompatActivity {
public final static int REQUEST_CODE = 10101;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (checkDrawOverlayPermission()) {
startService(new Intent(this, PowerButtonService.class));
}
}
public boolean checkDrawOverlayPermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (!Settings.canDrawOverlays(this)) {
/** if not construct intent to request permission */
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
/** request permission via start activity for result */
startActivityForResult(intent, REQUEST_CODE);
return false;
} else {
return true;
}
}
#Override
#TargetApi(Build.VERSION_CODES.M)
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (Settings.canDrawOverlays(this)) {
startService(new Intent(this, PowerButtonService.class));
}
}
}
}
Starting a service and adds a special view to WindowManager
Waiting for an action inside View's onCloseSystemDialogs method.
public class PowerButtonService extends Service {
public PowerButtonService() {
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
//home or recent button
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
Log.i("Key", "Long press on power button");
} else if ("homekey".equals(reason)) {
//home key pressed
} else if ("recentapss".equals(reason)) {
// recent apps button clicked
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
|| event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
|| event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Key", "keycode " + event.getKeyCode());
}
return super.dispatchKeyEvent(event);
}
};
mLinear.setFocusable(true);
View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="powerbuttonpress">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
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=".PowerButtonService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>
service_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
</LinearLayout>
Use Broadcast receiver for power button (Screen On/Off)event
here is solution: create broadcast receiver class
public class CallBroadCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//The screen off position
Toast.makeText(context,"Screen is off",Toast.LENGTH_LONG).show();
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//The screen on position
Toast.makeText(context,"Screen is on",Toast.LENGTH_LONG).show();
}
}}
then follow below steps:
1. Initialize receiver in activity
CallBroadCastReciever broadcastReceiver = new CallBroadCastReciever();
2.Declare receiver in manifest file in tag
<receiver android:name="com.android.CallBroadCastReciever">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
3.For send action and data from activity to receiver put below code in onCreate() or onStrat() method
IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
if (broadcastReceiver != null) {
registerReceiver(broadcastReceiver, intentFilter);
}}
4.Don't forget to unregister receiver in onDestory() method
protected void onDestroy() {
super.onDestroy();
if (broadcastReceiver != null) {
unregisterReceiver(broadcastReceiver);
} }
You could overwrite the public boolean onKeyDown(int keyCode, KeyEvent event) and public boolean onKeyUp(int keyCode, KeyEvent event) functions in your Activity class and test if keyCode is equal to KeyEvent.KEYCODE_POWER.
I haven't tested this, but I would assume the system treats this like it does the Home key in that you cannot stop the system from receiving the key event, you can only observe that it occurs. To test this, try returning True from the above functions and see if this catches the key event.
For all android versions use this code.
I tried R. Zagórski's answer, but I am not able to run this code on Pie. However, I have updated their code in my answer.
PowerButtonService:
public class PowerButtonService extends Service {
public PowerButtonService() {
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout mLinear = new LinearLayout(getApplicationContext()) {
//home or recent button
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
Log.i("Key", "Long press on power button");
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + "0000000000"));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_FROM_BACKGROUND);
startActivity(intent);
} else if ("homekey".equals(reason)) {
//home key pressed
} else if ("recentapss".equals(reason)) {
// recent apps button clicked
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP
|| event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN
|| event.getKeyCode() == KeyEvent.KEYCODE_CAMERA
|| event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
Log.i("Key", "keycode " + event.getKeyCode());
}
return super.dispatchKeyEvent(event);
}
};
mLinear.setFocusable(true);
**// here I done with EDIT**
int LAYOUT_FLAG;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
View mView = LayoutInflater.from(this).inflate(R.layout.service_layout, mLinear);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and service_layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:layout_height="match_parent">
</LinearLayout>
you have to use this:
BroadcastReceiver screenoff = new BroadcastReceiver() {
public static final String Screenoff = "android.intent.action.SCREEN_OFF";
#Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().equals(Screenoff)) return;
//put code to handle power press here
return;
}};
My Application needs to know if the screen went off due to timeout or the user clicked the power button.
I decided to check if the power button was pressed.
I read some Q&A here and came up with this :
public class MyActivity extends Activity {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
Log.w("Test", "Power button down detected");
return true;
}
return false;
}
#Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_POWER) {
Log.w("Test", "Power button up detected");
}
return false;
}
}
I also added this:
<uses-permission android:name="android.permission.PREVENT_POWER_KEY"/>
This doesn't work, it doesn't print the log.
Try to yseing from BroadcastReceiver:
public class MyBroadCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//DO HERE
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//DO HERE
}
}
}
and your manifest:
<receiver android:name=".MyBroadCastReciever">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
The onKeyDown method, no longer detects the single Power Key click. It does however detect the long press. Here's a very simple trick to capture it, and to differentiate from other buttons and other user's activities that would bring the app to the background.
PwrKeyShortPress = true; // set the default value in your class
....
....
#Override
public void onUserLeaveHint(){
PwrKeyShortPress = false;
super.onUserLeaveHint();
}
#Override
public void onStop() {
if (PwrKeyShortPress) {
// Do something for single Power Key click.
}
PwrKeyShortPress = true;
super.onStop();
}
go this way
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_POWER) {
// Power Button pressed
return true;
}
return super.onKeyDown(keyCode, event);
}
EDIT
you can listen to the screen ON/OFF this way
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//do something
}
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//do something else
}