Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

proximityMonitoring may not be working as intended

Tags:

ios

swift

swift2

for my iOS app i want to implement a feature where the screen should turns off (like when you answer a phone call) when the device is faced down. so I've started by detecting the device orientation:

//in my ViewDidLoad
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.rotated(_:)), name: UIDeviceOrientationDidChangeNotification, object: nil)

//called when the device changes orientation
    func rotated(notification: NSNotification){
        if UIDevice.currentDevice().orientation == UIDeviceOrientation.FaceDown{
            print("device = faced down")
        }else{
            print("device != faced down")
        }
    }

when device is down i've called

UIDevice.currentDevice().proximityMonitoringEnabled = true

else

UIDevice.currentDevice().proximityMonitoringEnabled = false

the problem is UIDeviceOrientationDidChangeNotification seems to act a little bit late so when the rotated() function is called, the device is already faced down and it turns out that in order for proximityMonitoringEnabled = true to turn off the screen the proximity sensor should not be already covered ! I'm pretty sure that this is an Apple limitation but maybe someone out there did found a solution or came across a workaround! thanks in advance.

like image 478
Med Abida Avatar asked Jul 23 '16 20:07

Med Abida


1 Answers

Approach:

Since iOS doesn't provide before changing Orientation we couldn't rely on 'UIDeviceOrientationDidChangeNotification'. Instead we can use CoreMotion Framework and access hardware's gyroscope for detecting possible FaceDown orientations and set proximityMonitoringEnabled appropriately.

Gyroscope Data:

Using Gyroscope observations below values can possibly detect FaceDown Orientation.

let gyroData = (minX:-3.78, minY:-3.38, minZ:-5.33, maxX:3.29, maxY:4.94, maxZ:3.36)

Solution in Swift:

class ProximityViewController: UIViewController {

    let cmManager = CMMotionManager(), gyroData = (minX:-3.78, minY:-3.38, minZ:-5.33, maxX:3.29, maxY:4.94, maxZ:3.36)

    override func viewDidLoad() {
        super.viewDidLoad()

        //Using GyroMotion
        experimentCoreMotion()
    }

    //MARK: - Using Core Motion
    func experimentCoreMotion() {

        if cmManager.gyroAvailable {

            //Enable device orientation notification
            UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications()

            cmManager.gyroUpdateInterval = 0.1

            handleFaceDownOrientation()

        }

    }

    func handleFaceDownOrientation() {

        cmManager.startGyroUpdatesToQueue(NSOperationQueue.currentQueue()!, withHandler: { (data:CMGyroData?, error: NSError?) in

            if self.isGyroDataInRange(data!) {

                UIDevice.currentDevice().proximityMonitoringEnabled = (UIDevice.currentDevice().orientation == .FaceDown)

                if UIDevice.currentDevice().orientation == .FaceDown {  print("FaceDown detected") }
                else { print("Orientation is not facedown") }
            }
        })
    }

    func isGyroDataInRange(val: CMGyroData) -> Bool {
        return ((val.rotationRate.x > gyroData.minX && val.rotationRate.x < gyroData.maxX) &&
            (val.rotationRate.y > gyroData.minY && val.rotationRate.y < gyroData.maxY) &&
            (val.rotationRate.z > gyroData.minZ && val.rotationRate.z < gyroData.maxZ))
    }
}

Hope my solution solves your query. Let me know the solution is working fine for your requirement.

Gyroscope & Accelerometer Observations:

I've experimented the possible values of FaceDown orientation using Gyroscope & Accelerometer. IMO, Gyroscope data seems fine but it's open to explore other hardware's sensors to detect FaceDown Orientation.

like image 60
Tesan3089 Avatar answered Oct 20 '22 00:10

Tesan3089