// Path: app/src/main/java/com/autonomousapps/common/LogUtil.java
// public class LogUtil {
// 
//     public static void v(@NonNull String tag, @NonNull String msg, @Nullable Object... args) {
//         Log.v(tag, String.format(msg, args));
//     }
// 
//     public static void d(@NonNull String tag, @NonNull String msg, @Nullable Object... args) {
//         Log.d(tag, String.format(msg, args));
//     }
// 
//     public static void e(@NonNull String tag, @NonNull String msg, @Nullable Object... args) {
//         Log.e(tag, String.format(msg, args));
//     }
// 
//     @NonNull
//     public static String asString(@Nullable Object obj) {
//         return obj != null ? obj.toString() : "null";
//     }
// }
// 
// Path: app/src/main/java/com/autonomousapps/reactivestopwatch/service/StopwatchService.java
// public class StopwatchService extends LifecycleLoggingService {
// 
//     private static final String TAG = StopwatchService.class.getSimpleName();
// 
//     @Inject
//     @Named("local")
//     Stopwatch stopwatch;
// 
//     private final CompositeSubscription subscriptions = new CompositeSubscription();
// 
//     boolean isRunning = false;
// 
//     @Override
//     public void onCreate() {
//         super.onCreate();
//         DaggerUtil.INSTANCE.getStopwatchComponent().inject(this);
//     }
// 
//     @Override
//     public int onStartCommand(Intent intent, int flags, int startId) {
//         super.onStartCommand(intent, flags, startId);
// 
//         return START_NOT_STICKY; // TODO which?
//     }
// 
//     @Override
//     public void onDestroy() {
//         subscriptions.clear();
//         super.onDestroy();
//     }
// 
//     @Nullable
//     @Override
//     public IBinder onBind(Intent intent) {
//         return binder;
//     }
// 
//     /**
//      * If {@link #stopwatch} is no longer running and all clients are unbound, stop service.
//      */
//     @Override
//     public boolean onUnbind(Intent intent) {
//         super.onUnbind(intent);
//         if (!isRunning) {
//             LogUtil.v(TAG + "_lifecycle", "stopSelf()");
//             stopSelf();
//         }
// 
//         return false; // False by default. True calls onRebind in future
//     }
// 
//     void setIsRunning(boolean isRunning) {
//         this.isRunning = isRunning;
//     }
// 
//     private final IStopwatchService.Stub binder = new IStopwatchService.Stub() {
// 
//         private IStopwatchTickListener listener;
// 
//         @Override
//         public void start(IStopwatchTickListener listener) throws RemoteException {
//             this.listener = listener;
// 
//             Subscription subscription = stopwatch.start().subscribe(this::onTick);
//             subscriptions.add(subscription);
// 
//             setIsRunning(true);
//         }
// 
//         private void onTick(long tick) {
//             try {
//                 listener.onTick(tick);
//             } catch (RemoteException e) {
//                 // TODO: more robust error handling
//                 LogUtil.e(TAG, "RemoteException calling listener::onTick: " + e.getLocalizedMessage());
//             }
//         }
// 
//         @Override
//         public void togglePause() throws RemoteException {
//             stopwatch.togglePause(); // TODO not idempotent. Should do nothing if not started/paused
//             setIsRunning(!isPaused());
//         }
// 
//         @Override
//         public boolean isPaused() throws RemoteException {
//             return stopwatch.isPaused();
//         }
// 
//         @Override
//         public void reset() throws RemoteException {
//             stopwatch.reset();
//             setIsRunning(false);
//         }
// 
//         @Override
//         public Lap lap() throws RemoteException {
//             return stopwatch.lap();
//         }
// 
//         @Override
//         public void close() {
//             stopwatch.close();
//         }
//     };
// }


import com.autonomousapps.common.LogUtil;
import com.autonomousapps.reactivestopwatch.service.IStopwatchService;
import com.autonomousapps.reactivestopwatch.service.IStopwatchTickListener;
import com.autonomousapps.reactivestopwatch.service.StopwatchService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import javax.inject.Inject;
import rx.Observable;
import rx.Subscription;
import rx.subjects.BehaviorSubject;
import rx.subjects.PublishSubject;
import rx.subscriptions.CompositeSubscription;
package com.autonomousapps.reactivestopwatch.time;





// Inspiration from http://www.donnfelker.com/rxjava-with-aidl-services/
// This also represents an implementation of the Adapter pattern.
public class RemoteStopwatch implements Stopwatch {

    private static final String TAG = RemoteStopwatch.class.getSimpleName();

    private final Context context;

    private IStopwatchService remoteService;
    private BehaviorSubject<IStopwatchService> serviceConnectionSubject = BehaviorSubject.create();

    private CompositeSubscription subscriptions;

    @Inject
    RemoteStopwatch(@NonNull Context context) {
        this.context = context;
        subscriptions = new CompositeSubscription();
        startService();
    }

    // I want the service to continue running even when unbound, so I start it first
    private void startService() {
        Intent serviceIntent = new Intent(context, StopwatchService.class);
        context.startService(serviceIntent);
    }

    @Override
    public void onUiShown() {
// Path: app/src/main/java/com/autonomousapps/common/LogUtil.java
// public class LogUtil {
// 
//     public static void v(@NonNull String tag, @NonNull String msg, @Nullable Object... args) {
//         Log.v(tag, String.format(msg, args));
//     }
// 
//     public static void d(@NonNull String tag, @NonNull String msg, @Nullable Object... args) {
//         Log.d(tag, String.format(msg, args));
//     }
// 
//     public static void e(@NonNull String tag, @NonNull String msg, @Nullable Object... args) {
//         Log.e(tag, String.format(msg, args));
//     }
// 
//     @NonNull
//     public static String asString(@Nullable Object obj) {
//         return obj != null ? obj.toString() : "null";
//     }
// }
// 
// Path: app/src/main/java/com/autonomousapps/reactivestopwatch/service/StopwatchService.java
// public class StopwatchService extends LifecycleLoggingService {
// 
//     private static final String TAG = StopwatchService.class.getSimpleName();
// 
//     @Inject
//     @Named("local")
//     Stopwatch stopwatch;
// 
//     private final CompositeSubscription subscriptions = new CompositeSubscription();
// 
//     boolean isRunning = false;
// 
//     @Override
//     public void onCreate() {
//         super.onCreate();
//         DaggerUtil.INSTANCE.getStopwatchComponent().inject(this);
//     }
// 
//     @Override
//     public int onStartCommand(Intent intent, int flags, int startId) {
//         super.onStartCommand(intent, flags, startId);
// 
//         return START_NOT_STICKY; // TODO which?
//     }
// 
//     @Override
//     public void onDestroy() {
//         subscriptions.clear();
//         super.onDestroy();
//     }
// 
//     @Nullable
//     @Override
//     public IBinder onBind(Intent intent) {
//         return binder;
//     }
// 
//     /**
//      * If {@link #stopwatch} is no longer running and all clients are unbound, stop service.
//      */
//     @Override
//     public boolean onUnbind(Intent intent) {
//         super.onUnbind(intent);
//         if (!isRunning) {
//             LogUtil.v(TAG + "_lifecycle", "stopSelf()");
//             stopSelf();
//         }
// 
//         return false; // False by default. True calls onRebind in future
//     }
// 
//     void setIsRunning(boolean isRunning) {
//         this.isRunning = isRunning;
//     }
// 
//     private final IStopwatchService.Stub binder = new IStopwatchService.Stub() {
// 
//         private IStopwatchTickListener listener;
// 
//         @Override
//         public void start(IStopwatchTickListener listener) throws RemoteException {
//             this.listener = listener;
// 
//             Subscription subscription = stopwatch.start().subscribe(this::onTick);
//             subscriptions.add(subscription);
// 
//             setIsRunning(true);
//         }
// 
//         private void onTick(long tick) {
//             try {
//                 listener.onTick(tick);
//             } catch (RemoteException e) {
//                 // TODO: more robust error handling
//                 LogUtil.e(TAG, "RemoteException calling listener::onTick: " + e.getLocalizedMessage());
//             }
//         }
// 
//         @Override
//         public void togglePause() throws RemoteException {
//             stopwatch.togglePause(); // TODO not idempotent. Should do nothing if not started/paused
//             setIsRunning(!isPaused());
//         }
// 
//         @Override
//         public boolean isPaused() throws RemoteException {
//             return stopwatch.isPaused();
//         }
// 
//         @Override
//         public void reset() throws RemoteException {
//             stopwatch.reset();
//             setIsRunning(false);
//         }
// 
//         @Override
//         public Lap lap() throws RemoteException {
//             return stopwatch.lap();
//         }
// 
//         @Override
//         public void close() {
//             stopwatch.close();
//         }
//     };
// }


// Path: app/src/main/java/com/autonomousapps/reactivestopwatch/time/RemoteStopwatch.java
import com.autonomousapps.common.LogUtil;
import com.autonomousapps.reactivestopwatch.service.IStopwatchService;
import com.autonomousapps.reactivestopwatch.service.IStopwatchTickListener;
import com.autonomousapps.reactivestopwatch.service.StopwatchService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import javax.inject.Inject;
import rx.Observable;
import rx.Subscription;
import rx.subjects.BehaviorSubject;
import rx.subjects.PublishSubject;
import rx.subscriptions.CompositeSubscription;

package com.autonomousapps.reactivestopwatch.time;





// Inspiration from http://www.donnfelker.com/rxjava-with-aidl-services/
// This also represents an implementation of the Adapter pattern.
public class RemoteStopwatch implements Stopwatch {

    private static final String TAG = RemoteStopwatch.class.getSimpleName();

    private final Context context;

    private IStopwatchService remoteService;
    private BehaviorSubject<IStopwatchService> serviceConnectionSubject = BehaviorSubject.create();

    private CompositeSubscription subscriptions;

    @Inject
    RemoteStopwatch(@NonNull Context context) {
        this.context = context;
        subscriptions = new CompositeSubscription();
        startService();
    }

    // I want the service to continue running even when unbound, so I start it first
    private void startService() {
        Intent serviceIntent = new Intent(context, StopwatchService.class);
        context.startService(serviceIntent);
    }

    @Override
    public void onUiShown() {
        Intent serviceIntent = new Intent(context, StopwatchService.class);