Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Programmatically disable the screen on/off magnetic sensor on Android

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?

like image 695
Budius Avatar asked Apr 04 '17 12:04

Budius


1 Answers

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.

like image 66
mayank1513 Avatar answered Oct 17 '22 01:10

mayank1513