// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.domokit.vsync;

import android.view.Choreographer;

import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.vsync.VSyncProvider;

/**
 * Android implementation of VSyncProvider.
 */
public class VSyncProviderImpl implements VSyncProvider, Choreographer.FrameCallback {
    private Choreographer mChoreographer;
    private AwaitVSyncResponse mCallback;
    private MessagePipeHandle mPipe;

    public VSyncProviderImpl(MessagePipeHandle pipe) {
        mPipe = pipe;
        mChoreographer = Choreographer.getInstance();
    }

    @Override
    public void close() {}

    @Override
    public void onConnectionError(MojoException e) {}

    @Override
    public void awaitVSync(final AwaitVSyncResponse callback) {
        if (mCallback != null) {
            mPipe.close();
            return;
        }
        mCallback = callback;
        mChoreographer.postFrameCallback(this);
    }

    @Override
    public void doFrame(long frameTimeNanos) {
        mCallback.call(frameTimeNanos / 1000);
        mCallback = null;
    }
}

// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.domokit.vsync;

import android.view.Choreographer;

import org.chromium.mojo.system.MessagePipeHandle;
import org.chromium.mojo.system.MojoException;
import org.chromium.mojom.vsync.VSyncProvider;

import java.util.ArrayList;

/**
 * Android implementation of VSyncProvider.
 */
public class VSyncProviderImpl implements VSyncProvider, Choreographer.FrameCallback {
    private Choreographer mChoreographer;
    private ArrayList<AwaitVSyncResponse> mCallbacks = new ArrayList<AwaitVSyncResponse>();
    private MessagePipeHandle mPipe;

    public VSyncProviderImpl(MessagePipeHandle pipe) {
        mPipe = pipe;
        mChoreographer = Choreographer.getInstance();
    }

    @Override
    public void close() {}

    @Override
    public void onConnectionError(MojoException e) {}

    @Override
    public void awaitVSync(final AwaitVSyncResponse callback) {
        mCallbacks.add(callback);
        if (mCallbacks.size() == 1) {
            mChoreographer.postFrameCallback(this);
        }
    }

    @Override
    public void doFrame(long frameTimeNanos) {
        long frameTimeMicros = frameTimeNanos / 1000;
        for (AwaitVSyncResponse callback : mCallbacks) {
            callback.call(frameTimeMicros);
        }
        mCallbacks.clear();
    }
}

Allow multiple callbacks in the VSyncProvider
Allow multiple callbacks in the VSyncProvider

It's possible for multiple calls to AwaitVSync to be pending while reloading
an application.  The Animator may get an AwaitVSync, a Reset, and then another
AwaitVSync before the first vsync completes.

If this happens, invoke both callbacks.  If we close the pipe, then the
Animator will no longer make progress.
