7

Several Android devices famously the Nexus series have a magnetic sensor that is NOT the android.hardware.Sensor.TYPE_MAGNETIC_FIELD used exclusively to turn the screen ON/OFF automatically using phone cases that have a small magnet inside them.

On my application, I'm using magnet detection using android.hardware.Sensor.TYPE_MAGNETIC_FIELD and the SensorManager to detect user touches the phone in a case with some magnets inside.

The code works without issues, the problem is that it's extremely easy on those devices to accidentally trigger the screen ON/OFF sensor thou, turning off the screen.

I've tried:

  • android:keepScreenOn="true" on the XML
  • using the permission android.permission.WAKE_LOCK and acquiring a wake-lock via PowerManager.

Both without success.

Is there a way to temporarily disable this sensor while my activity is resumed?

Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
Budius
  • 39,391
  • 16
  • 102
  • 144
  • AFAIK, it seems that Google provides no api to access the `Hall Effect Sensor`. – aminography Nov 25 '18 at 20:56
  • I use this for keeping screen on `getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)` – khalid3e Nov 26 '18 at 16:50
  • Is this problem only with your app? As you are trying to use this sensor – Mayank Kumar Chaudhari Nov 27 '18 at 10:27
  • @m__ I'm not trying to use the Hall Effect Sensor, we're using the normal `Sensor.TYPE_MAGNETIC_FIELD` to detect the user physically "tap" the phone on the hardware that the company sells (it's a door controller, that u can tap to open the door, so it contains a few magnets inside), but because of this other sensor that turns off the screen sometimes a tap on the door controller turns off the screen. – Budius Nov 27 '18 at 12:44
  • ok. I understand that keepScreenOn is also not working as the effect of this other sensor is same as manually pressing the screenlock button. – Mayank Kumar Chaudhari Nov 27 '18 at 13:07

2 Answers2

3

The keepScreenOn = true in manifest also doesn't work here as the action of hall effect sensor is same as pressing power button.

Here, I offer a work-around that I have tested. In this approach you display your activity regardless of hall-effect sensor locking the device and turning of the display.

Before beginning the unlocking action

getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
            WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
            WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

credits for above code - https://stackoverflow.com/a/45951927/9640177

Also make sure to add Permissions

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />

Setting these flags will make sure that your window will be visible above lockscreen.

Now, listen for ACTION_SCREEN_OFF intent. To do this add a broadcast receiver that listens for this intent broadcasted by the system. You need to register the receiver locally. (stackoverflow.com/a/9478013/9640177) in manifest

    <receiver android:name=".receiver">
        <intent-filter>
            <action android:name="android.intent.action.SCREEN_OFF"/>
        </intent-filter>
    </receiver>

Receiver class

public class receiver extends BroadcastReceiver {
  MyActivity activity;
  receiver(MyActivity activity){
    this.activity = activity;
  }
  @Override
  public void onReceive(final Context context, Intent intent) {
    activity.turnOnScreen();
  }
}

Inside activity

 // register receiver
 ...
 IntentFilter screenStateFilter = new IntentFilter();
    screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
    receiver r = new receiver(MyActivity.this);
    registerReceiver(r, screenStateFilter);
 ...
// function to turn on display
public void turnOnScreen(){
    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, "my:Tag");
    wakeLock.acquire();
    wakeLock.release();
}

credit - https://stackoverflow.com/a/44706632/9640177 This will turn the display on.

Don't forget to remove these flags after your activity has done the job and does not require to be in forefront.

getWindow().removeFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
            WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
            WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
            WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

This will make your window disappear from lock-screen and make the application function normally.

Hope this helps.

Community
  • 1
  • 1
Mayank Kumar Chaudhari
  • 16,027
  • 10
  • 55
  • 122
  • I hope this helps as it is applicable to all devices. Rooted as well as non-rooted. You need to add 10-20 extra lines of code to your app. And I hope this will improve experience of your users. – Mayank Kumar Chaudhari Dec 01 '18 at 15:32
  • Demo - https://play.google.com/store/apps/details?id=com.mayank.pdfviewer It turn on screen only once as the context is different and turning on screen might not be desirable in this case. – Mayank Kumar Chaudhari Dec 01 '18 at 17:47
  • Hi m_ I'm on purpose just let the bounty run and get auto-awarded for you with half the bounty because it's a somewhat viable workaround and I really appreciate the effort, but it's something that won't work on my specific case. I really needed the disable, and from what I could see from @Kousic answer is not possible is the real answer. My case is that we develop an SDK that other developers will use on their app, so all those "hack" on registering broadcast with the activity lifecycle is not an option. – Budius Dec 04 '18 at 19:12
  • Thanks for that. But are you able to manipulate the kernel without rooting the device??? – Mayank Kumar Chaudhari Dec 04 '18 at 20:36
  • I am not that familiar with development of ask but just curious. – Mayank Kumar Chaudhari Dec 04 '18 at 20:38
  • I'm not sure If this slove the **smart cover** issue, but I noticed that If you use `SYSTEM_ALERT_WINDOW`, you might need to add `WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY` to your flag ([source](https://developer.android.com/reference/android/Manifest.permission)). – Tokenyet Jul 03 '19 at 17:41
0

the most pragmatic solution to the problem might be ...

to disable the smart cover feature physically rather than by software.

eg. take a razorblade and tweezers and then remove the magnet.

... or simply get another cover without a magnet.

alternatively, file a bug against drivers/input/lid.c.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
  • I think it is like "plucking off the eye if the eye has cataract." why don't cure it. – Mayank Kumar Chaudhari Dec 01 '18 at 07:13
  • @m__ it depends, if we are talking about one single eye - or about many eyes. filing a bug against the vendor's ROM might be the best solution, in case they would agree. – Martin Zeitler Dec 01 '18 at 07:14
  • well you might prefer that. please try my answer. It bypasses the issue. Screen may be locked but the application doesn't suffer because of screen-locking. – Mayank Kumar Chaudhari Dec 01 '18 at 07:15
  • @m__ could imagine that to be working - nevertheless it's an overkill of a workaround, for a missing driver feature which might be high in demand. that's why I think one could convince the driver's vendor. https://source.android.com/setup/contribute/report-bugs – Martin Zeitler Dec 01 '18 at 07:20