/*
 * Copyright (C) 2015 Nathan VanBenschoten.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nvanbenschoten.rxsensor;

import android.annotation.TargetApi;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.CheckResult;
import android.support.annotation.NonNull;

import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;

/**
 * A lightweight wrapper around {@link SensorManager} which allows for continuously observing
 * the {@link SensorEvent} data.
 */
public final class RxSensorManager {

    private final Handler mSensorListenerHandler;
    private final SensorManager mSensorManager;

    public RxSensorManager(@NonNull SensorManager sensorManager) {
        mSensorListenerHandler = new Handler(Looper.getMainLooper());
        mSensorManager = sensorManager;
    }

    /**
     * Create an observable which will notify subscribers with a {@link SensorEvent}. Sensor
     * data will continue to be polled until the Observable's subscription is unsubscribed from.
     *
     * @see SensorManager#registerListener(SensorEventListener, Sensor, int)
     */
    @CheckResult
    public Observable<SensorEvent> observeSensor(final int sensorType,
                                                 final int samplingPeriodUs) {
        return observeSensor(sensorType, samplingPeriodUs, 0);
    }

    /**
     * Create an observable which will notify subscribers with a {@link SensorEvent}. Sensor
     * data will continue to be polled until the Observable's subscription is unsubscribed from.
     *
     * @see SensorManager#registerListener(SensorEventListener, Sensor, int, int)
     */
    @CheckResult
    public Observable<SensorEvent> observeSensor(final int sensorType,
                                                 final int samplingPeriodUs,
                                                 final int maxReportLatencyUs) {
        OnSubscribe<SensorEvent> subscribe = new OnSubscribe<SensorEvent>() {
            @TargetApi(VERSION_CODES.KITKAT)
            @Override
            public void call(final Subscriber<? super SensorEvent> subscriber) {
                // Determine Sensor to use
                final Sensor sensor = mSensorManager.getDefaultSensor(sensorType);
                if (sensor == null) {
                    subscriber.onError(new SensorException());
                    return;
                }

                // Create SensorEventListener that publishes onSensorChanged events to subscriber
                final SensorEventListener listener = new SensorEventListener() {
                    @Override
                    public void onSensorChanged(SensorEvent event) {
                        subscriber.onNext(event);
                    }

                    @Override
                    public void onAccuracyChanged(Sensor sensor, int accuracy) { }
                };

                // Attempt to register listener to SensorManager
                boolean success;
                if (Build.VERSION.SDK_INT >= VERSION_CODES.KITKAT) {
                    success = mSensorManager.registerListener(listener, sensor, samplingPeriodUs,
                            maxReportLatencyUs, mSensorListenerHandler);
                } else {
                    success = mSensorManager.registerListener(listener, sensor, samplingPeriodUs,
                            mSensorListenerHandler);
                }
                if (!success) {
                    subscriber.onError(new SensorException(sensor));
                    return;
                }

                // Set action on un-subscribe
                subscriber.add(Subscriptions.create(new Action0() {
                    @Override
                    public void call() {
                        mSensorManager.unregisterListener(listener, sensor);
                    }
                }));
            }
        };
        return Observable.create(subscribe)
                .lift(BackpressureBufferLastOperator.<SensorEvent>instance());
    }

}

@@ -827,24 +827,108 @@
 sorManager;%0A
+import android.hardware.TriggerEvent;%0Aimport android.hardware.TriggerEventListener;%0A
 import andro
@@ -4918,10 +4918,1970 @@
 %0A    %7D%0A%0A
+    /**%0A     * Create an observable which will notify subscribers with a %7B@link TriggerEvent%7D once and%0A     * then complete.%0A     *%0A     * @see SensorManager#requestTriggerSensor(TriggerEventListener, Sensor)%0A     */%0A    @CheckResult%0A    @TargetApi(VERSION_CODES.JELLY_BEAN_MR2)%0A    public Observable%3CTriggerEvent%3E observeTrigger(final int sensorType) %7B%0A        OnSubscribe%3CTriggerEvent%3E subscribe = new OnSubscribe%3CTriggerEvent%3E() %7B%0A            @Override%0A            public void call(final Subscriber%3C? super TriggerEvent%3E subscriber) %7B%0A                // Determine Sensor to use%0A                final Sensor sensor = mSensorManager.getDefaultSensor(sensorType);%0A                if (sensor == null) %7B%0A                    subscriber.onError(new SensorException());%0A                    return;%0A                %7D%0A%0A                // Create TriggerEventListener that publishes a single onTrigger events to%0A                // subscriber and completes%0A                final TriggerEventListener listener = new TriggerEventListener() %7B%0A                    @Override%0A                    public void onTrigger(TriggerEvent event) %7B%0A                        subscriber.onNext(event);%0A                        subscriber.onCompleted();%0A                    %7D%0A                %7D;%0A%0A                // Attempt to request a trigger sensor from SensorManager%0A                boolean success = mSensorManager.requestTriggerSensor(listener, sensor);%0A                if (!success) %7B%0A                    subscriber.onError(new SensorException(sensor));%0A                    return;%0A                %7D%0A%0A                // Set action on un-subscribe%0A                subscriber.add(Subscriptions.create(new Action0() %7B%0A                    @Override%0A                    public void call() %7B%0A                        mSensorManager.cancelTriggerSensor(listener, sensor);%0A                    %7D%0A                %7D));%0A            %7D%0A        %7D;%0A        return Observable.create(subscribe);%0A    %7D%0A%0A
 %7D%0A

Create observeTrigger method to wrap TriggerEventListener in Rx semantics