I am using this code to prevent dimming/locking screen, it is perfectly working for prevention of locking, but dimming effect is not prevented yet. please tell me some way out to prevent dimming also
protected void setScreenLock(boolean on){
if(mWakeLock == null){
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK |
PowerManager.ON_AFTER_RELEASE, TAG);
}
if(on){
mWakeLock.acquire();
}else{
if(mWakeLock.isHeld()){
mWakeLock.release();
}
mWakeLock = null;
}
}
Add
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
View root = findViewById(android.R.id.content);
if (root != null)
root.setKeepScreenOn(true);
to your if part. This won't allow the screen to be dimmed.
Do not use WakeLock at all (remove your current code and you can also get rid of related permission from your Manifest file) - this is incorrect (in most cases) approach. Use FLAG_KEEP_SCREEN_ON flag in your onCreate() to tell framework to manage this for you. Doc reads:
Window flag: as long as this window is visible to the user, keep the
device's screen turned on and bright.
like this:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Related
I am receiving a push notification, On that, calling a foreground service.
From the service, I am calling one Activity.
Here, I have 2 functionality.
1. Sound alarm for emergency
2. Call using ACTION_CALL.
Both are working fine if device unlocked.
But if a device is locked with password or pattern it did not work when push receives.
Below code to unlock the device. this method is called from onStart.
private void unlockDevice() {
KeyguardManager loKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
Window loWindow = this.getWindow();
if (Common.isAboveAPI27()) {
setShowWhenLocked(true);
setTurnScreenOn(true);
} else if (Common.isAboveAPI26()) {
loWindow.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
loWindow.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
dismissKeyguard(loKeyguardManager);
} else {
if (loKeyguardManager != null) {
KeyguardManager.KeyguardLock loKeyguardLock = loKeyguardManager.newKeyguardLock("FullWakeUps");
loKeyguardLock.disableKeyguard();
}
loWindow.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); // Deprecated in 26
loWindow.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED); // Deprecated in 27
loWindow.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); // Deprecated in 27
}
//Keep screen on
loWindow.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void dismissKeyguard(KeyguardManager loKeyguardManager) {
if (loKeyguardManager != null) {
loKeyguardManager.requestDismissKeyguard(SOSCallAndAlarmActivity.this, new KeyguardManager.KeyguardDismissCallback() {
#Override
public void onDismissError() {
super.onDismissError();
Log.i(TAG, Build.VERSION.SDK_INT + " : onDismissError");
}
#Override
public void onDismissSucceeded() {
super.onDismissSucceeded();
Log.i(TAG, Build.VERSION.SDK_INT + " : onDismissSucceeded");
}
#Override
public void onDismissCancelled() {
super.onDismissCancelled();
Log.i(TAG, Build.VERSION.SDK_INT + " : onDismissCancelled");
}
});
}
}
The below method is call in onDestroy to reenable the lock:
private void reEnabledKeyguard() {
KeyguardManager loKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (loKeyguardManager != null) {
KeyguardManager.KeyguardLock loKeyguardLock = loKeyguardManager.newKeyguardLock("FullWakeUps");
loKeyguardLock.reenableKeyguard();
}
Window loWindow = this.getWindow();
loWindow.addFlags(WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
Code to initiate the call.
public void callOnNumbers(String fsPhoneNumber) {
Intent loCallIntent = new Intent(Intent.ACTION_CALL);
loCallIntent.setData(Uri.parse("tel:" + fsPhoneNumber));
//callIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // tried this but not helped.
if (ActivityCompat.checkSelfPermission(CallAndAlarmActivity.this,
android.Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "call phone permission not granted");
return;
}
startActivity(loCallIntent);
}
Strange is when this method opens the call screen blink and again displays the password screen on lock screen simply press back button I can see the call screen.
I need to know one more thing, even I set all app killing option and disabled battery optimization. the same code did not execute on push receive.
When device inactive half an hour and if push receives, the above code did not even turn on light. when I click on the lock/unlock button I can see my screens properly. even I press it after 30 seconds of push receives time.
The problem facing from android N.
Additional
When the ACTION_CALL intent calls it to execute my activities onPause and I did not add any code in onPause and I can see one error in logcate
2020-04-27 16:23:47.400 25826-25826/app.safety E/ActivityThread: Performing stop of activity that is already stopped: {app.safety/app.safety.CallAndAlarmActivity}
java.lang.RuntimeException: Performing stop of activity that is already stopped: {app.safety/app.safety.CallAndAlarmActivity}
at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:4089)
at android.app.ActivityThread.handleStopActivity(ActivityThread.java:4177)
at android.app.ActivityThread.-wrap24(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1648)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6687)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:810)
2020-04-27 16:23:47.400 25826-25826/app.safety E/ActivityThread: ActivityClientRecord{paused=true, stopped=true, hideForNow=false, startsNotResumed=false, isForward=false, pendingConfigChanges=0, onlyLocalRequest=false, preserveWindow=false, Activity{resumed=false, stopped=true, finished=false, destroyed=false, startedActivity=false, temporaryPause=false, changingConfigurations=false}}
Thanks
I wonder if it has something to do with the Background Execution Limit. in Android. I would recommend looking at this article.
https://medium.com/exploring-android/exploring-background-execution-limits-on-android-oreo-ab384762a66c
I hope this is of any help.
I'm trying to figure out how to detect if the Display is Off on Android and I have a feeling that the Always-On Display on my S10 is affecting my results.
Currently, I'm using the logic found in this stackoverflow answer.
There is also a comment on that thread that says you should be able to use Display.FLAG_PRIVATE to check for Samsung's Always-On Display, but it doesn't explain how.
Using that information, I've put together this function. But it doesn't seem to work. The display seems to be counted as on almost always if i have the Always-On display enabled.
public boolean isScreenOn() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays()) {
if ((display.getFlags() & Display.FLAG_PRIVATE) != Display.FLAG_PRIVATE) {
if (display.getState() != Display.STATE_OFF) {
return true;
}
}
}
return false;
} else {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
//noinspection deprecation
return pm.isScreenOn();
}
}
I'm not sure if the way i'm checking the Display.FLAG_PRIVATE flag is correct, or if that will even help with the potential of the Always-On display affecting the result.
I found that the flags don't actually have anything to do with it. It seems that the display state will be one of several states including Display.STATE_DOZE_SUSPENDED, Display.STATE_DOZE and several others when the Always-On Display is active. So instead, I'm just checking for Display.STATE_ON and treating all other states as the display being turned off.
public boolean isScreenOn() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays()) {
if (display.getState() == Display.STATE_ON) {
return true;
}
}
return false;
} else {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
//noinspection deprecation
return pm.isScreenOn();
}
}
Android lint warns on the following with [Wakelock]:
public static void acquire(Context ctx, long timeout) {
if (wakeLock != null) {
wakeLock.release();
}
PowerManager powerManager
= (PowerManager) ctx.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP |
PowerManager.ON_AFTER_RELEASE,
Common.TAG);
wakeLock.setReferenceCounted(false);
if ( timeout <= 0 ) {
wakeLock.acquire();
} else {
wakeLock.acquire(timeout);
}
}
public static synchronized void release() {
if ( wakeLock != null ) {
if ( wakeLock.isHeld() ) {
wakeLock.release();
}
wakeLock = null;
}
}
It gives the warning for the first occurrence
[lint] [...]/WakeLocker.java: Warning: The release() call is not always reached [Wakelock]
Yet, it does not really need to be released every time, as there is a timeout.
The default solution of wrapping this in a try-catch-block, as for example in android-wakelock-not-released-after-getactivenetworkinfo, or in #rainash's answer below, do not address the problems that led to using this approach, namely that the device can go back to sleep.
How is this fixed? Or should it be ignored?
use try-catch block wrap task you execute when device awake
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "tag");
wakeLock.acquire();
try {
do something
} finally {
wakeLock.release();
}
});
Indeed this seems to be a long forgotten problem. In fact this bug was reported to google already back in 2013 here, but seems to still be there.
As one commenter states:
The following code get the warning:
try {
wakeLock.acquire();
...
} catch (Exception e) {
...
} finally {
wakeLock.release();
}
Results in:
The release() call is not always reached (via exceptional flow)
However, if you throw the Exception in a method, no warning is reported:
private void makeMistake() throws Exception {
throw new Exception();
...
try {
wakeLock.acquire();
makeMistake();
} catch (Exception e) {
...
} finally {
wakeLock.release();
}
}
To disable this warning, rather do it in your apps build.gradle file, for easy access, rather than inline as suggested by #user.
...
lintOptions {
disable 'Wakelock'
}
As #tyczj hinted:
[Lint] also flags issues that may or may not be a problem depending on the context.
So think about the warning, and
If you've manually verified that an issue is not a problem, you may
want to mark the issue as verified such that lint does not keep
pointing it out.
To remove the warning in this case, use
#SuppressLint("Wakelock")
public static void acquire(Context ctx, long timeout) {
with
import android.annotation.SuppressLint;
I've been writing tests with androids new espresso framework and find that it works well. One annoying thing (not particular to espresso) is that I have to make sure my screen is awake and unlocked for the tests to run. I found a workaround (through various sources) however I am not sure the best way to integrate it.
So this is what I did, in my "Home" activity I have the following code:
Home.class:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/************ Put this in a conditional for a test version ***********/
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock keyguardLock = km.newKeyguardLock("TAG");
keyguardLock.disableKeyguard();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
Also you need to add the following permissions:
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
So after doing this my tests now wake my phone up to run so I don't have to stand guard and make sure that the screen doesn't turn off right before the tests start.
I would rather not include those permissions though in my app obviously. I know with gradle it is possible to make different "flavors" that have their own android manifest which will merge into the main manifest. I was thinking of using that but I'd rather not add a flavor just for that reason given this is already using the test build type to run. It looks like from the android gradle documentation that you can't create an AndroidManifest for the instrumentTest directory as it will be auto generated.
However I was wondering if there is another way to do it without creating a variant and then specifying that the tests should run that variant. Also I'm not sure of the exact syntax of all that and thought it would be nice just to have this information on the site for others as it seems to be scattered about.
Lastly, if anyone knows of a better way of solving the issue of waking the phone up for the tests I'd love to hear it as I'm not a big fan of this way I'm attempting.
I actually figured out a really easy way to handle this. Remove the keyguard and wakelock permissions from the main manifest and put them in src/debug/AndroidManifest.xml like so:
src/debug/AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
</manifest>
When the app is built for debug the above permissions will merge into the main manifest. By default the build system uses the debug build for instrument tests so this works fine.
Then in my onCreate I put the code mentioned in the question:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (BuildConfig.DEBUG) {
KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock keyguardLock = km.newKeyguardLock("TAG");
keyguardLock.disableKeyguard();
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
...
}
Now my phone can run tests without me waking them up by hand first and I didn't have to add the above permissions to the release version of my app.
The easiest approach is to use adb command like below if you are running the tests from CI environment for example:
adb -s $DEVICE_ID shell input keyevent 82
This will unlock your device screen.
Now that KeyguardLock is deprecated, you can simply use:
if (BuildConfig.DEBUG) {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}
I've created the src/debug/AndroidManifest.xml file as Matt suggested and added to following code to the testCase:
#Override
public void setUp() throws Exception {
super.setUp();
// Espresso will not launch our activity for us, we must launch it via getActivity().
Activity activity = getActivity();
KeyguardManager km = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE);
KeyguardManager.KeyguardLock keyguardLock = km.newKeyguardLock("TAG");
keyguardLock.disableKeyguard();
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
Although you already have accepted Matt Wolve answer, I think that polluting your code with test boilerplate is not a good idea (I am aware that using Espresso there are some situations where you have to, like adding idle flags for custom IdlingResources). I would like to add another approach:
#ClassRule
public static ActivityTestRule<HomeActivity> mActivityRuleSetUp = new ActivityTestRule<>(
HomeActivity.class);
private static void wakeUpDevice(){
if (BuildConfig.DEBUG){
HomeActivity homeActivity = mActivityRuleSetUp.getActivity();
KeyguardManager myKM = (KeyguardManager) homeActivity.getSystemService(HomeActivity.KEYGUARD_SERVICE);
boolean isPhoneLocked = myKM.inKeyguardRestrictedInputMode();
if (isPhoneLocked){
homeActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
}
}
}
#BeforeClass
public static void setUp(){
wakeUpDevice();
}
Hope it helps.
Here is an approach that does not use any deprecated APIs, no manifest permissions, and works even if the device has a lock pin set.
Option 1: In #Before
#RunWith(AndroidJUnit4::class)
class MyActivityTest {
// Replace with your own Activity test rule.
#get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
#Before
fun setUp() {
UiDevice.getInstance(getInstrumentation()).wakeUp()
composeTestRule.activity.setShowWhenLocked(true)
}
}
Option 2: Rule
#RunWith(AndroidJUnit4::class)
class MyActivityTest {
#get:Rule
val composeTestRule = createAndroidComposeRule<MyActivity>()
#get:Rule
val screenLockRule = RunWhenScreenOffOrLockedRule()
}
/**
* This rule will allow the tests to run even if the device's screen is off or locked.
* Allows a developer to fire and forget running the UI Test across different devices or on the CI
* emulator.
*/
class RunWhenScreenOffOrLockedRule : TestRule {
override fun apply(base: Statement, description: Description): Statement {
return object : Statement() {
override fun evaluate() {
// Turn screen on
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()).wakeUp()
// Allow any activity to run when locked
ActivityLifecycleMonitorRegistry
.getInstance()
.addLifecycleCallback { activity, stage ->
if (stage === Stage.PRE_ON_CREATE) {
activity.setShowWhenLocked(true)
}
}
// Continue with other statements
base.evaluate()
}
}
}
}
For testing device set Lock pattern to NONE in Settings->Security
Then use instance of UiDevice and call its wakeUp() method
This method simulates pressing the power button if the screen is OFF else it does nothing if the screen is already ON. If the screen was OFF and it just got turned ON, this method will insert a 500ms delay to allow the device time to wake up and accept input.
Another best way to wake up device before test.
Simply add ActivityLifecycleCallback in your setUp method.
public class Moduletest extends ActivityInstrumentationTestCase2<Your Activity>{
protected void setUp(){
super.setUp();
ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(new ActivityLifecycleCallback() {
#Override public void onActivityLifecycleChanged(Activity activity, Stage stage) {
if (stage == Stage.PRE_ON_CREATE) {
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
});
}
}
I have done it this way: First make two rules, one for the activity and one for UI Thread:
#Rule
public ActivityTestRule<Your Activity> mActivityRule =
new ActivityTestRule<>(Your Activity.class, true, true);
#Rule
public UiThreadTestRule uiThreadTestRule = new UiThreadTestRule();
And then in my first test method made this:
#Test
#LargeTest
public void CreateAndSaveTaskEntity() throws Throwable {
uiThreadTestRule.runOnUiThread(new Runnable() {
#Override
public void run() {
Your Activity activity = mActivityRule.getActivity();
activity.getWindow()
.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}
});
//begin test cases
...
}
Of course you have to add in AndroidManifest.xml the permissions:
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
I'm developing an Android application that might be used at night. Therefor, I need to turn off the buttons' backlight. How can I do this? On my own phone the backlight turns off after a while, but on the Motorola Droid I don't think this happens.
I'm using a wakelock to keep the screen on. Should I use another flag or how can I do this?
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, WAKE_LOCK_TAG);
mWakeLock.acquire();
Thank you very much!
//Kaloer
There is a hack:
private void setDimButtons(boolean dimButtons) {
Window window = getWindow();
LayoutParams layoutParams = window.getAttributes();
float val = dimButtons ? 0 : -1;
try {
Field buttonBrightness = layoutParams.getClass().getField(
"buttonBrightness");
buttonBrightness.set(layoutParams, val);
} catch (Exception e) {
e.printStackTrace();
}
window.setAttributes(layoutParams);
}
I see that this is an old question that was mostly answered in a comment link, but to make it clear to anyone else who comes across this question, here's my own answer.
It's built-in since API 8. (doc)
float android.view.WindowManager.LayoutParams.buttonBrightness
This is a somewhat modified/simplified version of what I'm using in one of my apps (excluding irrelevant code). The inner class is required to prevent a crash at launch on older platforms that don't support it.
private void nightMode() {
Window win = getWindow();
LayoutParams lp = win.getAttributes();
if (prefs.getBoolean("Night", false))
changeBtnBacklight(lp, LayoutParams.BRIGHTNESS_OVERRIDE_OFF);
else changeBtnBacklight(lp, LayoutParams.BRIGHTNESS_OVERRIDE_NONE);
win.setAttributes(lp);
}
private void changeBtnBacklight(LayoutParams lp, float value) {
if (Integer.parseInt(Build.VERSION.SDK) >= 8) {
try {
new BtnBrightness(lp, value);
} catch (Exception e) {
Log.w(TAG, "Error changing button brightness");
e.printStackTrace();
}
}
}
private static class BtnBrightness {
BtnBrightness(LayoutParams lp, float v) {
lp.buttonBrightness = v;
}
}
AFAIK, there is no API to control the backlight of the buttons -- sorry!