/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "FakeInputPortService.h" #include "InputPortData.h" #include "mozilla/dom/InputPort.h" #include "nsIMutableArray.h" #include "nsITimer.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" namespace mozilla { namespace dom { namespace { class InputPortServiceNotifyRunnable final : public nsRunnable { public: InputPortServiceNotifyRunnable( nsIInputPortServiceCallback* aCallback, nsIArray* aDataList, uint16_t aErrorCode = nsIInputPortServiceCallback::INPUTPORT_ERROR_OK) : mCallback(aCallback) , mDataList(aDataList) , mErrorCode(aErrorCode) { MOZ_ASSERT(aCallback); MOZ_ASSERT(aDataList); } NS_IMETHOD Run() override { if (mErrorCode == nsIInputPortServiceCallback::INPUTPORT_ERROR_OK) { return mCallback->NotifySuccess(mDataList); } else { return mCallback->NotifyError(mErrorCode); } } private: nsCOMPtr mCallback; nsCOMPtr mDataList; uint16_t mErrorCode; }; class PortConnectionChangedCallback final : public nsITimerCallback { public: NS_DECL_ISUPPORTS PortConnectionChangedCallback(nsIInputPortData* aInputPortData, nsIInputPortListener* aInputPortListener, const bool aIsConnected) : mInputPortData(aInputPortData) , mInputPortListener(aInputPortListener) , mIsConnected(aIsConnected) {} NS_IMETHOD Notify(nsITimer* aTimer) override { InputPortData* portData = static_cast(mInputPortData.get()); portData->SetConnected(mIsConnected); nsresult rv = mInputPortListener->NotifyConnectionChanged( portData->GetId(), mIsConnected); return rv; } private: ~PortConnectionChangedCallback() {} nsCOMPtr mInputPortData; nsCOMPtr mInputPortListener; bool mIsConnected; }; } // namespace NS_IMPL_ISUPPORTS(PortConnectionChangedCallback, nsITimerCallback) NS_IMPL_CYCLE_COLLECTION_CLASS(FakeInputPortService) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FakeInputPortService) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortConnectionChangedTimer) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPortDatas) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FakeInputPortService) tmp->Shutdown(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mInputPortListener) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortConnectionChangedTimer) NS_IMPL_CYCLE_COLLECTION_UNLINK(mPortDatas) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTING_ADDREF(FakeInputPortService) NS_IMPL_CYCLE_COLLECTING_RELEASE(FakeInputPortService) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FakeInputPortService) NS_INTERFACE_MAP_ENTRY(nsIInputPortService) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END FakeInputPortService::FakeInputPortService() { Init(); } FakeInputPortService::~FakeInputPortService() { Shutdown(); } void FakeInputPortService::Init() { nsCOMPtr portData1 = MockInputPort(NS_LITERAL_STRING("1"), NS_LITERAL_STRING("av"), true); mPortDatas.AppendElement(portData1); nsCOMPtr portData2 = MockInputPort(NS_LITERAL_STRING("2"), NS_LITERAL_STRING("displayport"), false); mPortDatas.AppendElement(portData2); nsCOMPtr portData3 = MockInputPort(NS_LITERAL_STRING("3"), NS_LITERAL_STRING("hdmi"), true); mPortDatas.AppendElement(portData3); } void FakeInputPortService::Shutdown() { if (mPortConnectionChangedTimer) { mPortConnectionChangedTimer->Cancel(); } } /* virtual */ NS_IMETHODIMP FakeInputPortService::GetInputPortListener(nsIInputPortListener** aInputPortListener) { if (!mInputPortListener) { *aInputPortListener = nullptr; return NS_OK; } *aInputPortListener = mInputPortListener; NS_ADDREF(*aInputPortListener); return NS_OK; } /* virtual */ NS_IMETHODIMP FakeInputPortService::SetInputPortListener(nsIInputPortListener* aInputPortListener) { mInputPortListener = aInputPortListener; return NS_OK; } /* virtual */ NS_IMETHODIMP FakeInputPortService::GetInputPorts(nsIInputPortServiceCallback* aCallback) { if (!aCallback) { return NS_ERROR_INVALID_ARG; } nsCOMPtr portDataList = do_CreateInstance(NS_ARRAY_CONTRACTID); if (!portDataList) { return NS_ERROR_OUT_OF_MEMORY; } for (uint32_t i = 0; i < mPortDatas.Length(); i++) { portDataList->AppendElement(mPortDatas[i], false); } mPortConnectionChangedTimer = do_CreateInstance(NS_TIMER_CONTRACTID); NS_ENSURE_TRUE(mPortConnectionChangedTimer, NS_ERROR_OUT_OF_MEMORY); bool isConnected = false; mPortDatas[0]->GetConnected(&isConnected); //simulate the connection change event. RefPtr connectionChangedCb = new PortConnectionChangedCallback(mPortDatas[0], mInputPortListener, !isConnected); nsresult rv = mPortConnectionChangedTimer->InitWithCallback( connectionChangedCb, 100, nsITimer::TYPE_ONE_SHOT); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } nsCOMPtr runnable = new InputPortServiceNotifyRunnable(aCallback, portDataList); return NS_DispatchToCurrentThread(runnable); } already_AddRefed FakeInputPortService::MockInputPort(const nsAString& aId, const nsAString& aType, bool aIsConnected) { nsCOMPtr portData = new InputPortData(); portData->SetId(aId); portData->SetType(aType); portData->SetConnected(aIsConnected); return portData.forget(); } } // namespace dom } // namespace mozilla