diff options
Diffstat (limited to 'widget/gonk')
137 files changed, 0 insertions, 53584 deletions
diff --git a/widget/gonk/GeckoTouchDispatcher.cpp b/widget/gonk/GeckoTouchDispatcher.cpp deleted file mode 100644 index 0b18c91a1..000000000 --- a/widget/gonk/GeckoTouchDispatcher.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* Copyright 2014 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "FrameMetrics.h" -#include "GeckoProfiler.h" -#include "GeckoTouchDispatcher.h" -#include "InputData.h" -#include "ProfilerMarkers.h" -#include "base/basictypes.h" -#include "gfxPrefs.h" -#include "libui/Input.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Mutex.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/dom/Touch.h" -#include "mozilla/layers/APZThreadUtils.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "nsAppShell.h" -#include "nsDebug.h" -#include "nsThreadUtils.h" -#include "nsWindow.h" -#include <sys/types.h> -#include <unistd.h> -#include <utils/Timers.h> - -#undef LOG -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) - -// uncomment to print log resample data -// #define LOG_RESAMPLE_DATA 1 - -namespace mozilla { - -// Amount of time in MS before an input is considered expired. -static const uint64_t kInputExpirationThresholdMs = 1000; - -static StaticRefPtr<GeckoTouchDispatcher> sTouchDispatcher; - -/* static */ GeckoTouchDispatcher* -GeckoTouchDispatcher::GetInstance() -{ - if (!sTouchDispatcher) { - sTouchDispatcher = new GeckoTouchDispatcher(); - ClearOnShutdown(&sTouchDispatcher); - } - return sTouchDispatcher; -} - -GeckoTouchDispatcher::GeckoTouchDispatcher() - : mTouchQueueLock("GeckoTouchDispatcher::mTouchQueueLock") - , mHavePendingTouchMoves(false) - , mInflightNonMoveEvents(0) - , mTouchEventsFiltered(false) -{ - // Since GeckoTouchDispatcher is initialized when input is initialized - // and reads gfxPrefs, it is the first thing to touch gfxPrefs. - // The first thing to touch gfxPrefs MUST occur on the main thread and init - // the singleton - MOZ_ASSERT(sTouchDispatcher == nullptr); - MOZ_ASSERT(NS_IsMainThread()); - gfxPrefs::GetSingleton(); - - mEnabledUniformityInfo = gfxPrefs::UniformityInfo(); - mVsyncAdjust = TimeDuration::FromMilliseconds(gfxPrefs::TouchVsyncSampleAdjust()); - mMaxPredict = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMaxPredict()); - mMinDelta = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMinDelta()); - mOldTouchThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleOldTouchThreshold()); - mDelayedVsyncThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleVsyncDelayThreshold()); -} - -void -GeckoTouchDispatcher::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver) -{ - MOZ_ASSERT(NS_IsMainThread()); - // We assume on b2g that there is only 1 CompositorBridgeParent - MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); - mCompositorVsyncScheduler = aObserver; -} - -void -GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp) -{ - layers::APZThreadUtils::AssertOnControllerThread(); - DispatchTouchMoveEvents(aVsyncTimestamp); -} - -// Touch data timestamps are in milliseconds, aEventTime is in nanoseconds -void -GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime) -{ - if (mCompositorVsyncScheduler) { - mCompositorVsyncScheduler->SetNeedsComposite(); - } - - if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) { - MutexAutoLock lock(mTouchQueueLock); - if (mInflightNonMoveEvents > 0) { - // If we have any pending non-move events, we shouldn't resample the - // move events because we might end up dispatching events out of order. - // Instead, fall back to a non-resampling in-order dispatch until we're - // done processing the non-move events. - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod<MultiTouchInput>( - this, &GeckoTouchDispatcher::DispatchTouchEvent, aTouch)); - return; - } - - mTouchMoveEvents.push_back(aTouch); - mHavePendingTouchMoves = true; - } else { - { // scope lock - MutexAutoLock lock(mTouchQueueLock); - mInflightNonMoveEvents++; - } - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod<MultiTouchInput>( - this, &GeckoTouchDispatcher::DispatchTouchNonMoveEvent, aTouch)); - } -} - -void -GeckoTouchDispatcher::DispatchTouchNonMoveEvent(MultiTouchInput aInput) -{ - layers::APZThreadUtils::AssertOnControllerThread(); - - // Flush pending touch move events, if there are any - // (DispatchTouchMoveEvents will check the mHavePendingTouchMoves flag and - // bail out if there's nothing to be done). - NotifyVsync(TimeStamp::Now()); - DispatchTouchEvent(aInput); - - { // scope lock - MutexAutoLock lock(mTouchQueueLock); - mInflightNonMoveEvents--; - MOZ_ASSERT(mInflightNonMoveEvents >= 0); - } -} - -void -GeckoTouchDispatcher::DispatchTouchMoveEvents(TimeStamp aVsyncTime) -{ - MultiTouchInput touchMove; - - { - MutexAutoLock lock(mTouchQueueLock); - if (!mHavePendingTouchMoves) { - return; - } - mHavePendingTouchMoves = false; - - int touchCount = mTouchMoveEvents.size(); - TimeDuration vsyncTouchDiff = aVsyncTime - mTouchMoveEvents.back().mTimeStamp; - // The delay threshold is a positive pref, but we're testing to see if the - // vsync time is delayed from the touch, so add a negative sign. - bool isDelayedVsyncEvent = vsyncTouchDiff < -mDelayedVsyncThreshold; - bool isOldTouch = vsyncTouchDiff > mOldTouchThreshold; - bool resample = (touchCount > 1) && !isDelayedVsyncEvent && !isOldTouch; - - if (!resample) { - touchMove = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - if (!isDelayedVsyncEvent && !isOldTouch) { - mTouchMoveEvents.push_back(touchMove); - } - } else { - ResampleTouchMoves(touchMove, aVsyncTime); - } - } - - DispatchTouchEvent(touchMove); -} - -static int -Interpolate(int start, int end, TimeDuration aFrameDiff, TimeDuration aTouchDiff) -{ - return start + (((end - start) * aFrameDiff.ToMicroseconds()) / aTouchDiff.ToMicroseconds()); -} - -static const SingleTouchData& -GetTouchByID(const SingleTouchData& aCurrentTouch, MultiTouchInput& aOtherTouch) -{ - int32_t index = aOtherTouch.IndexOfTouch(aCurrentTouch.mIdentifier); - if (index < 0) { - // We can have situations where a previous touch event had 2 fingers - // and we lift 1 finger off. In those cases, we won't find the touch event - // with given id, so just return the current touch, which will be resampled - // without modification and dispatched. - return aCurrentTouch; - } - return aOtherTouch.mTouches[index]; -} - - -// aTouchDiff is the duration between the base and current touch times -// aFrameDiff is the duration between the base and the time we're resampling to -static void -ResampleTouch(MultiTouchInput& aOutTouch, - MultiTouchInput& aBase, MultiTouchInput& aCurrent, - TimeDuration aFrameDiff, TimeDuration aTouchDiff) -{ - aOutTouch = aCurrent; - - // Make sure we only resample the correct finger. - for (size_t i = 0; i < aOutTouch.mTouches.Length(); i++) { - const SingleTouchData& current = aCurrent.mTouches[i]; - const SingleTouchData& base = GetTouchByID(current, aBase); - - const ScreenIntPoint& baseTouchPoint = base.mScreenPoint; - const ScreenIntPoint& currentTouchPoint = current.mScreenPoint; - - ScreenIntPoint newSamplePoint; - newSamplePoint.x = Interpolate(baseTouchPoint.x, currentTouchPoint.x, aFrameDiff, aTouchDiff); - newSamplePoint.y = Interpolate(baseTouchPoint.y, currentTouchPoint.y, aFrameDiff, aTouchDiff); - - aOutTouch.mTouches[i].mScreenPoint = newSamplePoint; - -#ifdef LOG_RESAMPLE_DATA - const char* type = "extrapolate"; - if (aFrameDiff < aTouchDiff) { - type = "interpolate"; - } - - float alpha = aFrameDiff / aTouchDiff; - LOG("%s base (%d, %d), current (%d, %d) to (%d, %d) alpha %f, touch diff %d, frame diff %d\n", - type, - baseTouchPoint.x, baseTouchPoint.y, - currentTouchPoint.x, currentTouchPoint.y, - newSamplePoint.x, newSamplePoint.y, - alpha, (int)aTouchDiff.ToMilliseconds(), (int)aFrameDiff.ToMilliseconds()); -#endif - } -} - -/* - * +> Base touch (The touch before current touch) - * | - * | +> Current touch (Latest touch) - * | | - * | | +> Maximum resample time - * | | | - * +-----+------+--------------------> Time - * ^ ^ - * | | - * +------+--> Potential vsync events which the touches are resampled to - * | | - * | +> Extrapolation - * | - * +> Interpolation - */ - -void -GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp aVsyncTime) -{ - MOZ_RELEASE_ASSERT(mTouchMoveEvents.size() >= 2); - mTouchQueueLock.AssertCurrentThreadOwns(); - - MultiTouchInput currentTouch = mTouchMoveEvents.back(); - mTouchMoveEvents.pop_back(); - MultiTouchInput baseTouch = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - mTouchMoveEvents.push_back(currentTouch); - - TimeStamp sampleTime = aVsyncTime - mVsyncAdjust; - TimeDuration touchDiff = currentTouch.mTimeStamp - baseTouch.mTimeStamp; - - if (touchDiff < mMinDelta) { - aOutTouch = currentTouch; - #ifdef LOG_RESAMPLE_DATA - LOG("The touches are too close, skip resampling\n"); - #endif - return; - } - - if (currentTouch.mTimeStamp < sampleTime) { - TimeDuration maxResampleTime = std::min(touchDiff / int64_t(2), mMaxPredict); - TimeStamp maxTimestamp = currentTouch.mTimeStamp + maxResampleTime; - if (sampleTime > maxTimestamp) { - sampleTime = maxTimestamp; - #ifdef LOG_RESAMPLE_DATA - LOG("Overshot extrapolation time, adjusting sample time\n"); - #endif - } - } - - ResampleTouch(aOutTouch, baseTouch, currentTouch, sampleTime - baseTouch.mTimeStamp, touchDiff); - - // Both mTimeStamp and mTime are being updated to sampleTime here. - // mTime needs to be updated using a delta since TimeStamp doesn't - // provide a way to obtain a raw value. - aOutTouch.mTime += (sampleTime - aOutTouch.mTimeStamp).ToMilliseconds(); - aOutTouch.mTimeStamp = sampleTime; -} - -static bool -IsExpired(const MultiTouchInput& aTouch) -{ - // No pending events, the filter state can be updated. - uint64_t timeNowMs = systemTime(SYSTEM_TIME_MONOTONIC) / 1000000; - return (timeNowMs - aTouch.mTime) > kInputExpirationThresholdMs; -} -void -GeckoTouchDispatcher::DispatchTouchEvent(MultiTouchInput aMultiTouch) -{ - if ((aMultiTouch.mType == MultiTouchInput::MULTITOUCH_END || - aMultiTouch.mType == MultiTouchInput::MULTITOUCH_CANCEL) && - aMultiTouch.mTouches.Length() == 1) { - MutexAutoLock lock(mTouchQueueLock); - mTouchMoveEvents.clear(); - } else if (aMultiTouch.mType == MultiTouchInput::MULTITOUCH_START && - aMultiTouch.mTouches.Length() == 1) { - mTouchEventsFiltered = IsExpired(aMultiTouch); - } - - if (mTouchEventsFiltered) { - return; - } - - nsWindow::DispatchTouchInput(aMultiTouch); - - if (mEnabledUniformityInfo && profiler_is_active()) { - const char* touchAction = "Invalid"; - switch (aMultiTouch.mType) { - case MultiTouchInput::MULTITOUCH_START: - touchAction = "Touch_Event_Down"; - break; - case MultiTouchInput::MULTITOUCH_MOVE: - touchAction = "Touch_Event_Move"; - break; - case MultiTouchInput::MULTITOUCH_END: - case MultiTouchInput::MULTITOUCH_CANCEL: - touchAction = "Touch_Event_Up"; - break; - case MultiTouchInput::MULTITOUCH_SENTINEL: - MOZ_ASSERT_UNREACHABLE("Invalid MultTouchInput."); - break; - } - - const ScreenIntPoint& touchPoint = aMultiTouch.mTouches[0].mScreenPoint; - TouchDataPayload* payload = new TouchDataPayload(touchPoint); - PROFILER_MARKER_PAYLOAD(touchAction, payload); - } -} - -} // namespace mozilla diff --git a/widget/gonk/GeckoTouchDispatcher.h b/widget/gonk/GeckoTouchDispatcher.h deleted file mode 100644 index 3c7acd0e3..000000000 --- a/widget/gonk/GeckoTouchDispatcher.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* Copyright 2014 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GECKO_TOUCH_INPUT_DISPATCHER_h -#define GECKO_TOUCH_INPUT_DISPATCHER_h - -#include "InputData.h" -#include "Units.h" -#include "mozilla/Mutex.h" -#include <vector> -#include "mozilla/RefPtr.h" - -class nsIWidget; - -namespace mozilla { -namespace layers { -class CompositorVsyncScheduler; -} - -// Used to resample touch events whenever a vsync event occurs. It batches -// touch moves and on every vsync, resamples the touch position to create smooth -// scrolls. We use the Android touch resample algorithm. It uses a combination of -// extrapolation and interpolation. The algorithm takes the vsync time and -// subtracts mVsyncAdjust time in ms and creates a sample time. All touch events are -// relative to this sample time. If the last touch event occurs AFTER this -// sample time, interpolate the last two touch events. If the last touch event occurs BEFORE -// this sample time, we extrapolate the last two touch events to the sample -// time. The magic numbers defined as constants are taken from android -// InputTransport.cpp. -class GeckoTouchDispatcher final -{ - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoTouchDispatcher) - -public: - static GeckoTouchDispatcher* GetInstance(); - void NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime); - void DispatchTouchEvent(MultiTouchInput aMultiTouch); - void DispatchTouchNonMoveEvent(MultiTouchInput aInput); - void DispatchTouchMoveEvents(TimeStamp aVsyncTime); - void NotifyVsync(TimeStamp aVsyncTimestamp); - void SetCompositorVsyncScheduler(layers::CompositorVsyncScheduler* aObserver); - -protected: - ~GeckoTouchDispatcher() {} - -private: - GeckoTouchDispatcher(); - void ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp vsyncTime); - void SendTouchEvent(MultiTouchInput& aData); - void DispatchMouseEvent(MultiTouchInput& aMultiTouch, - bool aForwardToChildren); - - // mTouchQueueLock is used to protect the vector and state below - // as it is accessed on multiple threads. - Mutex mTouchQueueLock; - std::vector<MultiTouchInput> mTouchMoveEvents; - bool mHavePendingTouchMoves; - int mInflightNonMoveEvents; - // end stuff protected by mTouchQueueLock - - bool mResamplingEnabled; - bool mTouchEventsFiltered; - bool mEnabledUniformityInfo; - - // All times below are in nanoseconds - TimeDuration mVsyncAdjust; // Time from vsync we create sample times from - TimeDuration mMaxPredict; // How far into the future we're allowed to extrapolate - TimeDuration mMinDelta; // Minimal time difference between touches for resampling - - // Amount of time between vsync and the last event that is required before we - // resample - TimeDuration mMinResampleTime; - - // Threshold if a vsync event runs too far behind touch events - TimeDuration mDelayedVsyncThreshold; - - // How far ahead can vsync events get ahead of touch events. - TimeDuration mOldTouchThreshold; - - RefPtr<layers::CompositorVsyncScheduler> mCompositorVsyncScheduler; -}; - -} // namespace mozilla - -#endif // GECKO_TOUCH_INPUT_DISPATCHER_h diff --git a/widget/gonk/GfxInfo.cpp b/widget/gonk/GfxInfo.cpp deleted file mode 100644 index 7ddd39038..000000000 --- a/widget/gonk/GfxInfo.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 "GfxInfo.h" - -using namespace mozilla::widget; - -/* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after gfxPlatform initialization - * has occurred because they depend on it for information. (See bug 591561) */ -nsresult -GfxInfo::GetD2DEnabled(bool *aEnabled) -{ - return NS_ERROR_FAILURE; -} - -nsresult -GfxInfo::GetDWriteEnabled(bool *aEnabled) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription) -{ - aAdapterDescription.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM) -{ - aAdapterRAM.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver) -{ - aAdapterDriver.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) -{ - aAdapterDriverVersion.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate) -{ - aAdapterDriverDate.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID) -{ - aAdapterVendorID.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID) -{ - aAdapterDeviceID.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) -{ - return NS_ERROR_FAILURE; -} - -const nsTArray<GfxDriverInfo>& -GfxInfo::GetGfxDriverInfo() -{ - return *mDriverInfo; -} - -uint32_t GfxInfo::OperatingSystemVersion() -{ - return 0; -} - -nsresult -GfxInfo::GetFeatureStatusImpl(int32_t /*aFeature*/, - int32_t *aStatus, - nsAString & /*aSuggestedDriverVersion*/, - const nsTArray<GfxDriverInfo>& /*aDriverInfo*/, - nsACString& aFailureId, - OperatingSystem* /*aOS*/ /* = nullptr */) -{ - NS_ENSURE_ARG_POINTER(aStatus); - *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; - - return NS_OK; -} - -#ifdef DEBUG - -// Implement nsIGfxInfoDebug - -NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString &) -{ - return NS_OK; -} - -NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString &) -{ - return NS_OK; -} - -NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString &) -{ - return NS_OK; -} - -NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t) -{ - return NS_OK; -} - -#endif diff --git a/widget/gonk/GfxInfo.h b/widget/gonk/GfxInfo.h deleted file mode 100644 index 61494713f..000000000 --- a/widget/gonk/GfxInfo.h +++ /dev/null @@ -1,69 +0,0 @@ -/* vim: se cin sw=2 ts=2 et : */ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * 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/. */ - -#ifndef __mozilla_widget_GfxInfo_h__ -#define __mozilla_widget_GfxInfo_h__ - -#include "GfxInfoBase.h" -#include "GfxDriverInfo.h" - -#include "nsString.h" - -namespace mozilla { -namespace widget { - -class GfxInfo : public GfxInfoBase -{ -public: - // We only declare the subset of nsIGfxInfo that we actually implement. The - // rest is brought forward from GfxInfoBase. - NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled); - NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled); - NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion); - NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams); - NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription); - NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver); - NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID); - NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID); - NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID); - NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM); - NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion); - NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate); - NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription); - NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver); - NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID); - NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID); - NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID); - NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM); - NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion); - NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate); - NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active); - using GfxInfoBase::GetFeatureStatus; - using GfxInfoBase::GetFeatureSuggestedDriverVersion; - using GfxInfoBase::GetWebGLParameter; - - virtual uint32_t OperatingSystemVersion() override; - -#ifdef DEBUG - NS_DECL_NSIGFXINFODEBUG -#endif - -protected: - - virtual nsresult GetFeatureStatusImpl(int32_t aFeature, - int32_t *aStatus, - nsAString & aSuggestedDriverVersion, - const nsTArray<GfxDriverInfo>& aDriverInfo, - nsACString& aFailureId, - OperatingSystem* aOS = nullptr); - virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo(); -}; - -} // namespace widget -} // namespace mozilla - -#endif /* __mozilla_widget_GfxInfo_h__ */ diff --git a/widget/gonk/GonkClipboardData.cpp b/widget/gonk/GonkClipboardData.cpp deleted file mode 100644 index ced6422a5..000000000 --- a/widget/gonk/GonkClipboardData.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* 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 "GonkClipboardData.h" -#include "mozilla/gfx/DataSurfaceHelpers.h" - -namespace mozilla { - -void -GonkClipboardData::SetText(const nsAString &aText) -{ - mPlain = aText; -} - -bool -GonkClipboardData::HasText() const -{ - return !mPlain.IsEmpty(); -} - -const nsAString& -GonkClipboardData::GetText() const -{ - return mPlain; -} - -void -GonkClipboardData::SetHTML(const nsAString &aHTML) -{ - mHTML = aHTML; -} - -bool -GonkClipboardData::HasHTML() const -{ - return !mHTML.IsEmpty(); -} - -const nsAString& -GonkClipboardData::GetHTML() const -{ - return mHTML; -} - -void -GonkClipboardData::SetImage(gfx::DataSourceSurface* aDataSource) -{ - // Clone a new DataSourceSurface and store it. - mImage = gfx::CreateDataSourceSurfaceByCloning(aDataSource); -} - -bool -GonkClipboardData::HasImage() const -{ - return static_cast<bool>(mImage); -} - -already_AddRefed<gfx::DataSourceSurface> -GonkClipboardData::GetImage() const -{ - // Return cloned DataSourceSurface. - RefPtr<gfx::DataSourceSurface> cloned = gfx::CreateDataSourceSurfaceByCloning(mImage); - return cloned.forget(); -} - -void -GonkClipboardData::Clear() -{ - mPlain.Truncate(0); - mHTML.Truncate(0); - mImage = nullptr; -} - -} // namespace mozilla diff --git a/widget/gonk/GonkClipboardData.h b/widget/gonk/GonkClipboardData.h deleted file mode 100644 index 8bc1f1c9c..000000000 --- a/widget/gonk/GonkClipboardData.h +++ /dev/null @@ -1,49 +0,0 @@ -/* 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/. */ - -#ifndef mozilla_GonkClipboardData -#define mozilla_GonkClipboardData - -#include "mozilla/RefPtr.h" -#include "nsString.h" - -namespace mozilla { - -namespace gfx { -class DataSourceSurface; -} - -class GonkClipboardData final -{ -public: - explicit GonkClipboardData() = default; - ~GonkClipboardData() = default; - - // For text/plain - void SetText(const nsAString &aText); - bool HasText() const; - const nsAString& GetText() const; - - // For text/html - void SetHTML(const nsAString &aHTML); - bool HasHTML() const; - const nsAString& GetHTML() const; - - // For images - void SetImage(gfx::DataSourceSurface* aDataSource); - bool HasImage() const; - already_AddRefed<gfx::DataSourceSurface> GetImage() const; - - // For other APIs - void Clear(); - -private: - nsAutoString mPlain; - nsAutoString mHTML; - RefPtr<gfx::DataSourceSurface> mImage; -}; - -} // namespace mozilla - -#endif // mozilla_GonkClipboardData diff --git a/widget/gonk/GonkKeyMapping.h b/widget/gonk/GonkKeyMapping.h deleted file mode 100644 index d5d4e7a0b..000000000 --- a/widget/gonk/GonkKeyMapping.h +++ /dev/null @@ -1,301 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GONKKEYMAPPING_H -#define GONKKEYMAPPING_H - -#include "libui/android_keycodes.h" -#include "mozilla/EventForwards.h" - -namespace mozilla { -namespace widget { - -/* See libui/KeycodeLabels.h for the mapping */ -static const unsigned long kKeyMapping[] = { - 0, - 0, // SOFT_LEFT - 0, // SOFT_RIGHT - NS_VK_HOME, // HOME - NS_VK_ESCAPE, // BACK - 0, // CALL - NS_VK_SLEEP, // ENDCALL - NS_VK_0, - NS_VK_1, - NS_VK_2, - NS_VK_3, - NS_VK_4, - NS_VK_5, - NS_VK_6, - NS_VK_7, - NS_VK_8, - NS_VK_9, - NS_VK_ASTERISK, - NS_VK_HASH, - NS_VK_UP, - NS_VK_DOWN, - NS_VK_LEFT, - NS_VK_RIGHT, - NS_VK_RETURN, - NS_VK_VOLUME_UP, - NS_VK_VOLUME_DOWN, - NS_VK_SLEEP, // POWER - NS_VK_PRINTSCREEN, // CAMERA - NS_VK_CLEAR, - NS_VK_A, - NS_VK_B, - NS_VK_C, - NS_VK_D, - NS_VK_E, - NS_VK_F, - NS_VK_G, - NS_VK_H, - NS_VK_I, - NS_VK_J, - NS_VK_K, - NS_VK_L, - NS_VK_M, - NS_VK_N, - NS_VK_O, - NS_VK_P, - NS_VK_Q, - NS_VK_R, - NS_VK_S, - NS_VK_T, - NS_VK_U, - NS_VK_V, - NS_VK_W, - NS_VK_X, - NS_VK_Y, - NS_VK_Z, - NS_VK_COMMA, - NS_VK_PERIOD, - 0, - 0, - 0, - 0, - NS_VK_TAB, - NS_VK_SPACE, - NS_VK_META, // SYM - 0, // EXPLORER - 0, // ENVELOPE - NS_VK_RETURN, // ENTER - NS_VK_BACK, - NS_VK_BACK_QUOTE, // GRAVE - NS_VK_HYPHEN_MINUS, - NS_VK_EQUALS, - NS_VK_OPEN_BRACKET, - NS_VK_CLOSE_BRACKET, - NS_VK_BACK_SLASH, - NS_VK_SEMICOLON, - NS_VK_QUOTE, - NS_VK_SLASH, - NS_VK_AT, - 0, // NUM - NS_VK_F1, // HEADSETHOOK - 0, // FOCUS - NS_VK_PLUS, - NS_VK_CONTEXT_MENU, - 0, // NOTIFICATION - NS_VK_F5, // SEARCH - 0, // MEDIA_PLAY_PAUSE - 0, // MEDIA_STOP - 0, // MEDIA_NEXT - 0, // MEDIA_PREVIOUS - 0, // MEDIA_REWIND - 0, // MEDIA_FAST_FORWARD - 0, // MUTE - NS_VK_PAGE_UP, - NS_VK_PAGE_DOWN, - 0, // PICTSYMBOLS - 0, // SWITCH_CHARSET - 0, // BUTTON_A - 0, // BUTTON_B - 0, // BUTTON_C - 0, // BUTTON_X - 0, // BUTTON_Y - 0, // BUTTON_Z - 0, // BUTTON_L1 - 0, // BUTTON_R1 - 0, // BUTTON_L2 - 0, // BUTTON_R2 - 0, // BUTTON_THUMBL - 0, // BUTTON_THUMBR - 0, // BUTTON_START - 0, // BUTTON_SELECT - 0, // BUTTON_MODE - NS_VK_ESCAPE, - NS_VK_DELETE, - 0, // CTRL_LEFT - 0, // CTRL_RIGHT - NS_VK_CAPS_LOCK, - NS_VK_SCROLL_LOCK, - 0, // META_LEFT - 0, // META_RIGHT - 0, // FUNCTION - 0, // SYSRQ - 0, // BREAK - NS_VK_HOME, // MOVE_HOME - NS_VK_END, - NS_VK_INSERT, - 0, // FORWARD - 0, // MEDIA_PLAY - 0, // MEDIA_PAUSE - 0, // MEDIA_CLOSE - 0, // MEDIA_EJECT - 0, // MEDIA_RECORD - NS_VK_F1, - NS_VK_F2, - NS_VK_F3, - NS_VK_F4, - NS_VK_F5, - NS_VK_F6, - NS_VK_F7, - NS_VK_F8, - NS_VK_F9, - NS_VK_F10, - NS_VK_F11, - NS_VK_F12, - NS_VK_NUM_LOCK, - NS_VK_NUMPAD0, - NS_VK_NUMPAD1, - NS_VK_NUMPAD2, - NS_VK_NUMPAD3, - NS_VK_NUMPAD4, - NS_VK_NUMPAD5, - NS_VK_NUMPAD6, - NS_VK_NUMPAD7, - NS_VK_NUMPAD8, - NS_VK_NUMPAD9, - NS_VK_DIVIDE, - NS_VK_MULTIPLY, - NS_VK_SUBTRACT, - NS_VK_ADD, - NS_VK_PERIOD, - NS_VK_COMMA, - NS_VK_RETURN, - NS_VK_EQUALS, - 0, // NUMPAD_LEFT_PAREN - 0, // NUMPAD_RIGHT_PAREN - NS_VK_VOLUME_MUTE, - // There are more but we don't map them -}; - -static KeyNameIndex GetKeyNameIndex(int aKeyCode) -{ - switch (aKeyCode) { -#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ - case aNativeKey: return aKeyNameIndex; - -#include "NativeKeyToDOMKeyName.h" - -#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX - - case AKEYCODE_0: - case AKEYCODE_1: - case AKEYCODE_2: - case AKEYCODE_3: - case AKEYCODE_4: - case AKEYCODE_5: - case AKEYCODE_6: - case AKEYCODE_7: - case AKEYCODE_8: - case AKEYCODE_9: - case AKEYCODE_STAR: - case AKEYCODE_POUND: - case AKEYCODE_A: - case AKEYCODE_B: - case AKEYCODE_C: - case AKEYCODE_D: - case AKEYCODE_E: - case AKEYCODE_F: - case AKEYCODE_G: - case AKEYCODE_H: - case AKEYCODE_I: - case AKEYCODE_J: - case AKEYCODE_K: - case AKEYCODE_L: - case AKEYCODE_M: - case AKEYCODE_N: - case AKEYCODE_O: - case AKEYCODE_P: - case AKEYCODE_Q: - case AKEYCODE_R: - case AKEYCODE_S: - case AKEYCODE_T: - case AKEYCODE_U: - case AKEYCODE_V: - case AKEYCODE_W: - case AKEYCODE_X: - case AKEYCODE_Y: - case AKEYCODE_Z: - case AKEYCODE_COMMA: - case AKEYCODE_PERIOD: - case AKEYCODE_SPACE: - case AKEYCODE_GRAVE: - case AKEYCODE_MINUS: - case AKEYCODE_EQUALS: - case AKEYCODE_LEFT_BRACKET: - case AKEYCODE_RIGHT_BRACKET: - case AKEYCODE_BACKSLASH: - case AKEYCODE_SEMICOLON: - case AKEYCODE_APOSTROPHE: - case AKEYCODE_SLASH: - case AKEYCODE_AT: - case AKEYCODE_PLUS: - case AKEYCODE_NUMPAD_0: - case AKEYCODE_NUMPAD_1: - case AKEYCODE_NUMPAD_2: - case AKEYCODE_NUMPAD_3: - case AKEYCODE_NUMPAD_4: - case AKEYCODE_NUMPAD_5: - case AKEYCODE_NUMPAD_6: - case AKEYCODE_NUMPAD_7: - case AKEYCODE_NUMPAD_8: - case AKEYCODE_NUMPAD_9: - case AKEYCODE_NUMPAD_DIVIDE: - case AKEYCODE_NUMPAD_MULTIPLY: - case AKEYCODE_NUMPAD_SUBTRACT: - case AKEYCODE_NUMPAD_ADD: - case AKEYCODE_NUMPAD_DOT: - case AKEYCODE_NUMPAD_COMMA: - case AKEYCODE_NUMPAD_EQUALS: - case AKEYCODE_NUMPAD_LEFT_PAREN: - case AKEYCODE_NUMPAD_RIGHT_PAREN: - return KEY_NAME_INDEX_USE_STRING; - - default: - return KEY_NAME_INDEX_Unidentified; - } -} - -static CodeNameIndex GetCodeNameIndex(int aScanCode) -{ - switch (aScanCode) { -#define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \ - case aNativeKey: return aCodeNameIndex; - -#include "NativeKeyToDOMCodeName.h" - -#undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX - - default: - return CODE_NAME_INDEX_UNKNOWN; - } -} - -} // namespace widget -} // namespace mozilla - -#endif /* GONKKEYMAPPING_H */ diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp deleted file mode 100644 index 0fafb37cf..000000000 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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 <android/log.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <sys/sysinfo.h> - -#include "GonkMemoryPressureMonitoring.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Monitor.h" -#include "mozilla/Preferences.h" -#include "mozilla/ProcessPriorityManager.h" -#include "mozilla/Services.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsMemoryPressure.h" -#include "nsPrintfCString.h" -#include "nsThreadUtils.h" - -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "GonkMemoryPressure" , ## args) - -using namespace mozilla; - -namespace { - -/** - * MemoryPressureWatcher watches sysfs from its own thread to notice when the - * system is under memory pressure. When we observe memory pressure, we use - * MemoryPressureRunnable to notify observers that they should release memory. - * - * When the system is under memory pressure, we don't want to constantly fire - * memory-pressure events. So instead, we try to detect when sysfs indicates - * that we're no longer under memory pressure, and only then start firing events - * again. - * - * (This is a bit problematic because we can't poll() to detect when we're no - * longer under memory pressure; instead we have to periodically read the sysfs - * node. If we remain under memory pressure for a long time, this means we'll - * continue waking up to read from the node for a long time, potentially wasting - * battery life. Hopefully we don't hit this case in practice! We write to - * logcat each time we go around this loop so it's at least noticable.) - * - * Shutting down safely is a bit of a chore. XPCOM won't shut down until all - * threads exit, so we need to exit the Run() method below on shutdown. But our - * thread might be blocked in one of two situations: We might be poll()'ing the - * sysfs node waiting for memory pressure to occur, or we might be asleep - * waiting to read() the sysfs node to see if we're no longer under memory - * pressure. - * - * To let us wake up from the poll(), we poll() not just the sysfs node but also - * a pipe, which we write to on shutdown. To let us wake up from sleeping - * between read()s, we sleep by Wait()'ing on a monitor, which we notify on - * shutdown. - */ -class MemoryPressureWatcher final - : public nsIRunnable - , public nsIObserver -{ -public: - MemoryPressureWatcher() - : mMonitor("MemoryPressureWatcher") - , mLowMemTriggerKB(0) - , mPageSize(0) - , mShuttingDown(false) - , mTriggerFd(-1) - , mShutdownPipeRead(-1) - , mShutdownPipeWrite(-1) - { - } - - NS_DECL_THREADSAFE_ISUPPORTS - - nsresult Init() - { - nsCOMPtr<nsIObserverService> os = services::GetObserverService(); - NS_ENSURE_STATE(os); - - // The observer service holds us alive. - os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, /* ownsWeak */ false); - - // Initialize the internal state - mPageSize = sysconf(_SC_PAGESIZE); - ReadPrefs(); - nsresult rv = OpenFiles(); - NS_ENSURE_SUCCESS(rv, rv); - SetLowMemTrigger(mSoftLowMemTriggerKB); - - return NS_OK; - } - - NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) - { - MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); - LOG("Observed XPCOM shutdown."); - - MonitorAutoLock lock(mMonitor); - mShuttingDown = true; - mMonitor.Notify(); - - int rv; - do { - // Write something to the pipe; doesn't matter what. - uint32_t dummy = 0; - rv = write(mShutdownPipeWrite, &dummy, sizeof(dummy)); - } while(rv == -1 && errno == EINTR); - - return NS_OK; - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - int triggerResetTimeout = -1; - bool memoryPressure; - nsresult rv = CheckForMemoryPressure(&memoryPressure); - NS_ENSURE_SUCCESS(rv, rv); - - while (true) { - // Wait for a notification on mTriggerFd or for data to be written to - // mShutdownPipeWrite. (poll(mTriggerFd, POLLPRI) blocks until we're - // under memory pressure or until we time out, the time out is used - // to adjust the trigger level after a memory pressure event.) - struct pollfd pollfds[2]; - pollfds[0].fd = mTriggerFd; - pollfds[0].events = POLLPRI; - pollfds[1].fd = mShutdownPipeRead; - pollfds[1].events = POLLIN; - - int pollRv = MOZ_TEMP_FAILURE_RETRY( - poll(pollfds, ArrayLength(pollfds), triggerResetTimeout) - ); - - if (pollRv == 0) { - // Timed out, adjust the trigger and update the timeout. - triggerResetTimeout = AdjustTrigger(triggerResetTimeout); - continue; - } - - if (pollfds[1].revents) { - // Something was written to our shutdown pipe; we're outta here. - LOG("shutting down (1)"); - return NS_OK; - } - - // If pollfds[1] isn't happening, pollfds[0] ought to be! - if (!(pollfds[0].revents & POLLPRI)) { - LOG("Unexpected revents value after poll(): %d. " - "Shutting down GonkMemoryPressureMonitoring.", pollfds[0].revents); - return NS_ERROR_FAILURE; - } - - // POLLPRI on mTriggerFd indicates that we're in a low-memory situation. - // We could read lowMemFd to double-check, but we've observed that the - // read sometimes completes after the memory-pressure event is over, so - // let's just believe the result of poll(). - rv = DispatchMemoryPressure(MemPressure_New); - NS_ENSURE_SUCCESS(rv, rv); - - // Move to the hard level if we're on the soft one. - if (mLowMemTriggerKB > mHardLowMemTriggerKB) { - SetLowMemTrigger(mHardLowMemTriggerKB); - } - - // Manually check mTriggerFd until we observe that memory pressure is - // over. We won't fire any more low-memory events until we observe that - // we're no longer under pressure. Instead, we fire low-memory-ongoing - // events, which cause processes to keep flushing caches but will not - // trigger expensive GCs and other attempts to save memory that are - // likely futile at this point. - do { - { - MonitorAutoLock lock(mMonitor); - - // We need to check mShuttingDown before we wait here, in order to - // catch a shutdown signal sent after we poll()'ed mShutdownPipeRead - // above but before we started waiting on the monitor. But we don't - // need to check after we wait, because we'll either do another - // iteration of this inner loop, in which case we'll check - // mShuttingDown, or we'll exit this loop and do another iteration - // of the outer loop, in which case we'll check the shutdown pipe. - if (mShuttingDown) { - LOG("shutting down (2)"); - return NS_OK; - } - mMonitor.Wait(PR_MillisecondsToInterval(mPollMS)); - } - - LOG("Checking to see if memory pressure is over."); - rv = CheckForMemoryPressure(&memoryPressure); - NS_ENSURE_SUCCESS(rv, rv); - - if (memoryPressure) { - rv = DispatchMemoryPressure(MemPressure_Ongoing); - NS_ENSURE_SUCCESS(rv, rv); - continue; - } - } while (false); - - if (XRE_IsParentProcess()) { - // The main process will try to adjust the trigger. - triggerResetTimeout = mPollMS * 2; - } - - LOG("Memory pressure is over."); - } - - return NS_OK; - } - -protected: - ~MemoryPressureWatcher() {} - -private: - void ReadPrefs() { - // While we're under memory pressure, we periodically read() - // notify_trigger_active to try and see when we're no longer under memory - // pressure. mPollMS indicates how many milliseconds we wait between those - // read()s. - Preferences::AddUintVarCache(&mPollMS, - "gonk.systemMemoryPressureRecoveryPollMS", /* default */ 5000); - - // We have two values for the notify trigger, a soft one which is triggered - // before we start killing background applications and an hard one which is - // after we've killed background applications but before we start killing - // foreground ones. - Preferences::AddUintVarCache(&mSoftLowMemTriggerKB, - "gonk.notifySoftLowMemUnderKB", /* default */ 43008); - Preferences::AddUintVarCache(&mHardLowMemTriggerKB, - "gonk.notifyHardLowMemUnderKB", /* default */ 14336); - } - - nsresult OpenFiles() { - mTriggerFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active", - O_RDONLY | O_CLOEXEC); - NS_ENSURE_STATE(mTriggerFd != -1); - - int pipes[2]; - NS_ENSURE_STATE(!pipe(pipes)); - mShutdownPipeRead = pipes[0]; - mShutdownPipeWrite = pipes[1]; - return NS_OK; - } - - /** - * Set the low memory trigger to the specified value, this can be done by - * the main process alone. - */ - void SetLowMemTrigger(uint32_t aValue) { - if (XRE_IsParentProcess()) { - nsPrintfCString str("%ld", (aValue * 1024) / mPageSize); - if (WriteSysFile("/sys/module/lowmemorykiller/parameters/notify_trigger", - str.get())) { - mLowMemTriggerKB = aValue; - } - } - } - - /** - * Read from the trigger file descriptor and determine whether we're - * currently under memory pressure. - * - * We don't expect this method to block. - */ - nsresult CheckForMemoryPressure(bool* aOut) - { - *aOut = false; - - lseek(mTriggerFd, 0, SEEK_SET); - - char buf[2]; - int nread = MOZ_TEMP_FAILURE_RETRY(read(mTriggerFd, buf, sizeof(buf))); - NS_ENSURE_STATE(nread == 2); - - // The notify_trigger_active sysfs node should contain either "0\n" or - // "1\n". The latter indicates memory pressure. - *aOut = (buf[0] == '1'); - return NS_OK; - } - - int AdjustTrigger(int timeout) - { - if (!XRE_IsParentProcess()) { - return -1; // Only the main process can adjust the trigger. - } - - struct sysinfo info; - int rv = sysinfo(&info); - if (rv < 0) { - return -1; // Without system information we're blind, bail out. - } - - size_t freeMemory = (info.freeram * info.mem_unit) / 1024; - - if (freeMemory > mSoftLowMemTriggerKB) { - SetLowMemTrigger(mSoftLowMemTriggerKB); - return -1; // Trigger adjusted, wait indefinitely. - } - - // Wait again but double the duration, max once per day. - return std::min(86400000, timeout * 2); - } - - /** - * Dispatch the specified memory pressure event unless a high-priority - * process is present. If a high-priority process is present then it's likely - * responding to an urgent event (an incoming call or message for example) so - * avoid wasting CPU time responding to low-memory events. - */ - nsresult DispatchMemoryPressure(MemoryPressureState state) - { - if (ProcessPriorityManager::AnyProcessHasHighPriority()) { - return NS_OK; - } - - return NS_DispatchMemoryPressure(state); - } - - Monitor mMonitor; - uint32_t mPollMS; // Ongoing pressure poll delay - uint32_t mSoftLowMemTriggerKB; // Soft memory pressure level - uint32_t mHardLowMemTriggerKB; // Hard memory pressure level - uint32_t mLowMemTriggerKB; // Current value of the trigger - size_t mPageSize; - bool mShuttingDown; - - ScopedClose mTriggerFd; - ScopedClose mShutdownPipeRead; - ScopedClose mShutdownPipeWrite; -}; - -NS_IMPL_ISUPPORTS(MemoryPressureWatcher, nsIRunnable, nsIObserver); - -} // namespace - -namespace mozilla { - -void -InitGonkMemoryPressureMonitoring() -{ - // memoryPressureWatcher is held alive by the observer service. - RefPtr<MemoryPressureWatcher> memoryPressureWatcher = - new MemoryPressureWatcher(); - NS_ENSURE_SUCCESS_VOID(memoryPressureWatcher->Init()); - - nsCOMPtr<nsIThread> thread; - NS_NewNamedThread("MemoryPressure", getter_AddRefs(thread), - memoryPressureWatcher); -} - -} // namespace mozilla diff --git a/widget/gonk/GonkMemoryPressureMonitoring.h b/widget/gonk/GonkMemoryPressureMonitoring.h deleted file mode 100644 index 4d5149cd6..000000000 --- a/widget/gonk/GonkMemoryPressureMonitoring.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=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/. */ - -#ifndef mozilla_GonkMemoryPressureMonitoring_h_ -#define mozilla_GonkMemoryPressureMonitoring_h_ - -namespace mozilla { -void InitGonkMemoryPressureMonitoring(); -} - -#endif /* mozilla_GonkMemoryPressureMonitoring_h_ */ diff --git a/widget/gonk/GonkPermission.cpp b/widget/gonk/GonkPermission.cpp deleted file mode 100644 index 8ebc43de8..000000000 --- a/widget/gonk/GonkPermission.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2012 Mozilla Foundation - * - * 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. - */ - -#include "GonkPermission.h" -#include <binder/IPCThreadState.h> -#include <binder/ProcessState.h> -#include <binder/IServiceManager.h> -#include <binder/IPermissionController.h> - -#ifndef HAVE_ANDROID_OS -#define HAVE_ANDROID_OS 1 -#endif -#include <private/android_filesystem_config.h> - -#include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/TabParent.h" -#include "mozilla/SyncRunnable.h" -#include "nsIAppsService.h" -#include "mozIApplication.h" -#include "nsThreadUtils.h" - -#undef LOG -#include <android/log.h> -#undef ALOGE -#define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args) - -using namespace android; -using namespace mozilla; - -// Checking permissions needs to happen on the main thread, but the -// binder callback is called on a special binder thread, so we use -// this runnable for that. -class GonkPermissionChecker : public Runnable { - int32_t mPid; - bool mCanUseCamera; - - explicit GonkPermissionChecker(int32_t pid) - : mPid(pid) - , mCanUseCamera(false) - { - } - -public: - static already_AddRefed<GonkPermissionChecker> Inspect(int32_t pid) - { - RefPtr<GonkPermissionChecker> that = new GonkPermissionChecker(pid); - nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); - MOZ_ASSERT(mainThread); - SyncRunnable::DispatchToThread(mainThread, that); - return that.forget(); - } - - bool CanUseCamera() - { - return mCanUseCamera; - } - - NS_IMETHOD Run(); -}; - -NS_IMETHODIMP -GonkPermissionChecker::Run() -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Find our ContentParent. - dom::ContentParent *contentParent = nullptr; - { - nsTArray<dom::ContentParent*> parents; - dom::ContentParent::GetAll(parents); - for (uint32_t i = 0; i < parents.Length(); ++i) { - if (parents[i]->Pid() == mPid) { - contentParent = parents[i]; - break; - } - } - } - if (!contentParent) { - ALOGE("pid=%d denied: can't find ContentParent", mPid); - return NS_OK; - } - - // Now iterate its apps... - const ManagedContainer<dom::PBrowserParent>& browsers = - contentParent->ManagedPBrowserParent(); - for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) { - dom::TabParent *tabParent = - static_cast<dom::TabParent*>(iter.Get()->GetKey()); - nsCOMPtr<mozIApplication> mozApp = tabParent->GetOwnOrContainingApp(); - if (!mozApp) { - continue; - } - - // ...and check if any of them has camera access. - bool appCanUseCamera; - nsresult rv = mozApp->HasPermission("camera", &appCanUseCamera); - if (NS_SUCCEEDED(rv) && appCanUseCamera) { - mCanUseCamera = true; - return NS_OK; - } - } - return NS_OK; -} - -bool -GonkPermissionService::checkPermission(const String16& permission, int32_t pid, - int32_t uid) -{ - // root can do anything. - if (0 == uid) { - return true; - } - - String8 perm8(permission); - - // Some ril implementations need android.permission.MODIFY_AUDIO_SETTINGS - if ((uid == AID_SYSTEM || uid == AID_RADIO || uid == AID_BLUETOOTH) && - perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") { - return true; - } - - // No other permissions apply to non-app processes. - if (uid < AID_APP) { - ALOGE("%s for pid=%d,uid=%d denied: not an app", - String8(permission).string(), pid, uid); - return false; - } - - // Only these permissions can be granted to apps through this service. - if (perm8 != "android.permission.CAMERA" && - perm8 != "android.permission.RECORD_AUDIO") { - ALOGE("%s for pid=%d,uid=%d denied: unsupported permission", - String8(permission).string(), pid, uid); - return false; - } - - // Users granted the permission through a prompt dialog. - // Before permission managment of gUM is done, app cannot remember the - // permission. - PermissionGrant permGrant(perm8.string(), pid); - if (nsTArray<PermissionGrant>::NoIndex != mGrantArray.IndexOf(permGrant)) { - mGrantArray.RemoveElement(permGrant); - return true; - } - - // Camera/audio record permissions are allowed for apps with the - // "camera" permission. - RefPtr<GonkPermissionChecker> checker = - GonkPermissionChecker::Inspect(pid); - bool canUseCamera = checker->CanUseCamera(); - if (!canUseCamera) { - ALOGE("%s for pid=%d,uid=%d denied: not granted by user or app manifest", - String8(permission).string(), pid, uid); - } - return canUseCamera; -} - -static GonkPermissionService* gGonkPermissionService = NULL; - -/* static */ -void -GonkPermissionService::instantiate() -{ - defaultServiceManager()->addService(String16(getServiceName()), - GetInstance()); -} - -/* static */ -GonkPermissionService* -GonkPermissionService::GetInstance() -{ - if (!gGonkPermissionService) { - gGonkPermissionService = new GonkPermissionService(); - } - return gGonkPermissionService; -} - -void -GonkPermissionService::addGrantInfo(const char* permission, int32_t pid) -{ - mGrantArray.AppendElement(PermissionGrant(permission, pid)); -} diff --git a/widget/gonk/GonkPermission.h b/widget/gonk/GonkPermission.h deleted file mode 100644 index d34fcd8ac..000000000 --- a/widget/gonk/GonkPermission.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2012 Mozilla Foundation - * - * 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. - */ -#ifndef GONKPERMISSION_H -#define GONKPERMISSION_H - -#include <binder/BinderService.h> -#include "nsString.h" -#include "nsTArray.h" - -namespace mozilla { -class PermissionGrant -{ -public: - PermissionGrant(const char* perm, int32_t p) : mPid(p) - { - mPermission.Assign(perm); - } - - PermissionGrant(const nsACString& permission, int32_t pid) : mPid(pid), - mPermission(permission) - { - } - - bool operator==(const PermissionGrant& other) const - { - return (mPid == other.pid() && mPermission.Equals(other.permission())); - } - - int32_t pid() const - { - return mPid; - } - - const nsACString& permission() const - { - return mPermission; - } - -private: - int32_t mPid; - nsCString mPermission; -}; - -class PermissionGrant; - -class GonkPermissionService : - public android::BinderService<GonkPermissionService>, - public android::BnPermissionController -{ -public: - virtual ~GonkPermissionService() {} - static GonkPermissionService* GetInstance(); - static const char *getServiceName() { - return "permission"; - } - - static void instantiate(); - - virtual android::status_t dump(int fd, const android::Vector<android::String16>& args) { - return android::NO_ERROR; - } - virtual bool checkPermission(const android::String16& permission, int32_t pid, - int32_t uid); - - void addGrantInfo(const char* permission, int32_t pid); -private: - GonkPermissionService(): android::BnPermissionController() {} - nsTArray<PermissionGrant> mGrantArray; -}; - -} // namespace mozilla - -#endif // GONKPERMISSION_H diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp deleted file mode 100644 index 6b4c7a1cc..000000000 --- a/widget/gonk/HwcComposer2D.cpp +++ /dev/null @@ -1,971 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2012, 2013 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#include <android/log.h> -#include <string.h> - -#include "gfxPrefs.h" -#include "ImageLayers.h" -#include "libdisplay/GonkDisplay.h" -#include "HwcComposer2D.h" -#include "LayerScope.h" -#include "Units.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/LayerManagerComposite.h" -#include "mozilla/layers/PLayerTransaction.h" -#include "mozilla/layers/ShadowLayerUtilsGralloc.h" -#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL -#include "mozilla/StaticPtr.h" -#include "nsThreadUtils.h" -#include "cutils/properties.h" -#include "gfx2DGlue.h" -#include "gfxPlatform.h" -#include "VsyncSource.h" -#include "nsScreenManagerGonk.h" -#include "nsWindow.h" - -#if ANDROID_VERSION >= 17 -#include "libdisplay/DisplaySurface.h" -#endif - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "HWComposer" - -/* - * By default the debug message of hwcomposer (LOG_DEBUG level) are undefined, - * but can be enabled by uncommenting HWC_DEBUG below. - */ -//#define HWC_DEBUG - -#ifdef HWC_DEBUG -#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args) -#else -#define LOGD(args...) ((void)0) -#endif - -#define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) - -#define LAYER_COUNT_INCREMENTS 5 - -using namespace android; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace mozilla { - -static void -HookInvalidate(const struct hwc_procs* aProcs) -{ - HwcComposer2D::GetInstance()->Invalidate(); -} - -static void -HookVsync(const struct hwc_procs* aProcs, int aDisplay, - int64_t aTimestamp) -{ - HwcComposer2D::GetInstance()->Vsync(aDisplay, aTimestamp); -} - -static void -HookHotplug(const struct hwc_procs* aProcs, int aDisplay, - int aConnected) -{ - HwcComposer2D::GetInstance()->Hotplug(aDisplay, aConnected); -} - -static StaticRefPtr<HwcComposer2D> sInstance; - -HwcComposer2D::HwcComposer2D() - : mList(nullptr) - , mMaxLayerCount(0) - , mColorFill(false) - , mRBSwapSupport(false) - , mPrepared(false) - , mHasHWVsync(false) - , mLock("mozilla.HwcComposer2D.mLock") -{ - mHal = HwcHALBase::CreateHwcHAL(); - if (!mHal->HasHwc()) { - LOGD("no hwc support"); - return; - } - - RegisterHwcEventCallback(); - - nsIntSize screenSize; - - GonkDisplay::NativeData data = GetGonkDisplay()->GetNativeData(GonkDisplay::DISPLAY_PRIMARY); - ANativeWindow *win = data.mNativeWindow.get(); - win->query(win, NATIVE_WINDOW_WIDTH, &screenSize.width); - win->query(win, NATIVE_WINDOW_HEIGHT, &screenSize.height); - mScreenRect = gfx::IntRect(gfx::IntPoint(0, 0), screenSize); - - mColorFill = mHal->Query(HwcHALBase::QueryType::COLOR_FILL); - mRBSwapSupport = mHal->Query(HwcHALBase::QueryType::RB_SWAP); -} - -HwcComposer2D::~HwcComposer2D() -{ - free(mList); -} - -HwcComposer2D* -HwcComposer2D::GetInstance() -{ - if (!sInstance) { -#ifdef HWC_DEBUG - // Make sure only create once - static int timesCreated = 0; - ++timesCreated; - MOZ_ASSERT(timesCreated == 1); -#endif - LOGI("Creating new instance"); - sInstance = new HwcComposer2D(); - - // If anyone uses the compositor thread to create HwcComposer2D, - // we just skip this function. - // If ClearOnShutdown() can handle objects in other threads - // in the future, we can remove this check. - if (NS_IsMainThread()) { - // If we create HwcComposer2D by the main thread, we can use - // ClearOnShutdown() to make sure it will be nullified properly. - ClearOnShutdown(&sInstance); - } - } - return sInstance; -} - -bool -HwcComposer2D::EnableVsync(bool aEnable) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!mHasHWVsync) { - return false; - } - return mHal->EnableVsync(aEnable) && aEnable; -} - -bool -HwcComposer2D::RegisterHwcEventCallback() -{ - const HwcHALProcs_t cHWCProcs = { - &HookInvalidate, // 1st: void (*invalidate)(...) - &HookVsync, // 2nd: void (*vsync)(...) - &HookHotplug // 3rd: void (*hotplug)(...) - }; - mHasHWVsync = mHal->RegisterHwcEventCallback(cHWCProcs); - return mHasHWVsync; -} - -void -HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp) -{ - // Only support hardware vsync on kitkat, L and up due to inaccurate timings - // with JellyBean. -#if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) - TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(aVsyncTimestamp); - gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().NotifyVsync(vsyncTime); -#else - // If this device doesn't support vsync, this function should not be used. - MOZ_ASSERT(false); -#endif -} - -// Called on the "invalidator" thread (run from HAL). -void -HwcComposer2D::Invalidate() -{ - if (!mHal->HasHwc()) { - LOGE("HwcComposer2D::Invalidate failed!"); - return; - } - - MutexAutoLock lock(mLock); - if (mCompositorBridgeParent) { - mCompositorBridgeParent->ScheduleRenderOnCompositorThread(); - } -} - -namespace { -class HotplugEvent : public Runnable { -public: - HotplugEvent(GonkDisplay::DisplayType aType, bool aConnected) - : mType(aType) - , mConnected(aConnected) - { - } - - NS_IMETHOD Run() override - { - RefPtr<nsScreenManagerGonk> screenManager = - nsScreenManagerGonk::GetInstance(); - if (mConnected) { - screenManager->AddScreen(mType); - } else { - screenManager->RemoveScreen(mType); - } - return NS_OK; - } -private: - GonkDisplay::DisplayType mType; - bool mConnected; -}; -} // namespace - -void -HwcComposer2D::Hotplug(int aDisplay, int aConnected) -{ - NS_DispatchToMainThread(new HotplugEvent(GonkDisplay::DISPLAY_EXTERNAL, - aConnected)); -} - -void -HwcComposer2D::SetCompositorBridgeParent(CompositorBridgeParent* aCompositorBridgeParent) -{ - MutexAutoLock lock(mLock); - mCompositorBridgeParent = aCompositorBridgeParent; -} - -bool -HwcComposer2D::ReallocLayerList() -{ - int size = sizeof(HwcList) + - ((mMaxLayerCount + LAYER_COUNT_INCREMENTS) * sizeof(HwcLayer)); - - HwcList* listrealloc = (HwcList*)realloc(mList, size); - - if (!listrealloc) { - return false; - } - - if (!mList) { - //first alloc, initialize - listrealloc->numHwLayers = 0; - listrealloc->flags = 0; - } - - mList = listrealloc; - mMaxLayerCount += LAYER_COUNT_INCREMENTS; - return true; -} - -bool -HwcComposer2D::PrepareLayerList(Layer* aLayer, - const nsIntRect& aClip, - const Matrix& aParentTransform, - bool aFindSidebandStreams) -{ - // NB: we fall off this path whenever there are container layers - // that require intermediate surfaces. That means all the - // GetEffective*() coordinates are relative to the framebuffer. - - bool fillColor = false; - - const nsIntRegion visibleRegion = aLayer->GetLocalVisibleRegion().ToUnknownRegion(); - if (visibleRegion.IsEmpty()) { - return true; - } - - uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); - if (opacity == 0) { - LOGD("%s Layer has zero opacity; skipping", aLayer->Name()); - return true; - } - - if (!mHal->SupportTransparency() && opacity < 0xFF && !aFindSidebandStreams) { - LOGD("%s Layer has planar semitransparency which is unsupported by hwcomposer", aLayer->Name()); - return false; - } - - if (aLayer->GetMaskLayer() && !aFindSidebandStreams) { - LOGD("%s Layer has MaskLayer which is unsupported by hwcomposer", aLayer->Name()); - return false; - } - - nsIntRect clip; - nsIntRect layerClip = aLayer->GetLocalClipRect().valueOr(ParentLayerIntRect()).ToUnknownRect(); - nsIntRect* layerClipPtr = aLayer->GetLocalClipRect() ? &layerClip : nullptr; - if (!HwcUtils::CalculateClipRect(aParentTransform, - layerClipPtr, - aClip, - &clip)) - { - LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); - return true; - } - - // HWC supports only the following 2D transformations: - // - // Scaling via the sourceCrop and displayFrame in HwcLayer - // Translation via the sourceCrop and displayFrame in HwcLayer - // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags - // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags - // - // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes - // above - Matrix layerTransform; - if (!aLayer->GetEffectiveTransform().Is2D(&layerTransform) || - !layerTransform.PreservesAxisAlignedRectangles()) { - LOGD("Layer EffectiveTransform has a 3D transform or a non-square angle rotation"); - return false; - } - - Matrix layerBufferTransform; - if (!aLayer->GetEffectiveTransformForBuffer().Is2D(&layerBufferTransform) || - !layerBufferTransform.PreservesAxisAlignedRectangles()) { - LOGD("Layer EffectiveTransformForBuffer has a 3D transform or a non-square angle rotation"); - return false; - } - - if (ContainerLayer* container = aLayer->AsContainerLayer()) { - if (container->UseIntermediateSurface() && !aFindSidebandStreams) { - LOGD("Container layer needs intermediate surface"); - return false; - } - AutoTArray<Layer*, 12> children; - container->SortChildrenBy3DZOrder(children); - - for (uint32_t i = 0; i < children.Length(); i++) { - if (!PrepareLayerList(children[i], clip, layerTransform, aFindSidebandStreams) && - !aFindSidebandStreams) { - return false; - } - } - return true; - } - - LayerRenderState state = aLayer->GetRenderState(); - -#if ANDROID_VERSION >= 21 - if (!state.GetGrallocBuffer() && !state.GetSidebandStream().IsValid()) { -#else - if (!state.GetGrallocBuffer()) { -#endif - if (aLayer->AsColorLayer() && mColorFill) { - fillColor = true; - } else { - LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); - return false; - } - } - - nsIntRect visibleRect = visibleRegion.GetBounds(); - - nsIntRect bufferRect; - if (fillColor) { - bufferRect = nsIntRect(visibleRect); - } else { - nsIntRect layerRect; - if (state.mHasOwnOffset) { - bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, - state.mSize.width, state.mSize.height); - layerRect = bufferRect; - } else { - //Since the buffer doesn't have its own offset, assign the whole - //surface size as its buffer bounds - bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); - layerRect = bufferRect; - if (aLayer->GetType() == Layer::TYPE_IMAGE) { - ImageLayer* imageLayer = static_cast<ImageLayer*>(aLayer); - if(imageLayer->GetScaleMode() != ScaleMode::SCALE_NONE) { - layerRect = nsIntRect(0, 0, imageLayer->GetScaleToSize().width, imageLayer->GetScaleToSize().height); - } - } - } - // In some cases the visible rect assigned to the layer can be larger - // than the layer's surface, e.g., an ImageLayer with a small Image - // in it. - visibleRect.IntersectRect(visibleRect, layerRect); - } - - // Buffer rotation is not to be confused with the angled rotation done by a transform matrix - // It's a fancy PaintedLayer feature used for scrolling - if (state.BufferRotated()) { - LOGD("%s Layer has a rotated buffer", aLayer->Name()); - return false; - } - - const bool needsYFlip = state.OriginBottomLeft() ? true - : false; - - hwc_rect_t sourceCrop, displayFrame; - if(!HwcUtils::PrepareLayerRects(visibleRect, - layerTransform, - layerBufferTransform, - clip, - bufferRect, - needsYFlip, - &(sourceCrop), - &(displayFrame))) - { - return true; - } - - // OK! We can compose this layer with hwc. - int current = mList ? mList->numHwLayers : 0; - - // Do not compose any layer below full-screen Opaque layer - // Note: It can be generalized to non-fullscreen Opaque layers. - bool isOpaque = opacity == 0xFF && - (state.mFlags & LayerRenderStateFlags::OPAQUE); - // Currently we perform opacity calculation using the *bounds* of the layer. - // We can only make this assumption if we're not dealing with a complex visible region. - bool isSimpleVisibleRegion = visibleRegion.Contains(visibleRect); - if (current && isOpaque && isSimpleVisibleRegion) { - nsIntRect displayRect = nsIntRect(displayFrame.left, displayFrame.top, - displayFrame.right - displayFrame.left, displayFrame.bottom - displayFrame.top); - if (displayRect.Contains(mScreenRect)) { - // In z-order, all previous layers are below - // the current layer. We can ignore them now. - mList->numHwLayers = current = 0; - mHwcLayerMap.Clear(); - } - } - - if (!mList || current >= mMaxLayerCount) { - if (!ReallocLayerList() || current >= mMaxLayerCount) { - LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); - return false; - } - } - - HwcLayer& hwcLayer = mList->hwLayers[current]; - hwcLayer.displayFrame = displayFrame; - mHal->SetCrop(hwcLayer, sourceCrop); - buffer_handle_t handle = nullptr; -#if ANDROID_VERSION >= 21 - if (state.GetSidebandStream().IsValid()) { - handle = state.GetSidebandStream().GetRawNativeHandle(); - } else if (state.GetGrallocBuffer()) { - handle = state.GetGrallocBuffer()->getNativeBuffer()->handle; - } -#else - if (state.GetGrallocBuffer()) { - handle = state.GetGrallocBuffer()->getNativeBuffer()->handle; - } -#endif - hwcLayer.handle = handle; - - hwcLayer.flags = 0; - hwcLayer.hints = 0; - hwcLayer.blending = isOpaque ? HWC_BLENDING_NONE : HWC_BLENDING_PREMULT; -#if ANDROID_VERSION >= 17 - hwcLayer.compositionType = HWC_FRAMEBUFFER; -#if ANDROID_VERSION >= 21 - if (state.GetSidebandStream().IsValid()) { - hwcLayer.compositionType = HWC_SIDEBAND; - } -#endif - hwcLayer.acquireFenceFd = -1; - hwcLayer.releaseFenceFd = -1; -#if ANDROID_VERSION >= 18 - hwcLayer.planeAlpha = opacity; -#endif -#else - hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; -#endif - - if (!fillColor) { - if (state.FormatRBSwapped()) { - if (!mRBSwapSupport) { - LOGD("No R/B swap support in H/W Composer"); - return false; - } - hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; - } - - // Translation and scaling have been addressed in PrepareLayerRects(). - // Given the above and that we checked for PreservesAxisAlignedRectangles() - // the only possible transformations left to address are - // square angle rotation and horizontal/vertical reflection. - // - // The rotation and reflection permutations total 16 but can be - // reduced to 8 transformations after eliminating redundancies. - // - // All matrices represented here are in the form - // - // | xx xy | - // | yx yy | - // - // And ignore scaling. - // - // Reflection is applied before rotation - gfx::Matrix rotation = layerTransform; - // Compute fuzzy zero like PreservesAxisAlignedRectangles() - if (fabs(rotation._11) < 1e-6) { - if (rotation._21 < 0) { - if (rotation._12 > 0) { - // 90 degree rotation - // - // | 0 -1 | - // | 1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_90; - LOGD("Layer rotated 90 degrees"); - } - else { - // Horizontal reflection then 90 degree rotation - // - // | 0 -1 | | -1 0 | = | 0 -1 | - // | 1 0 | | 0 1 | | -1 0 | - // - // same as vertical reflection then 270 degree rotation - // - // | 0 1 | | 1 0 | = | 0 -1 | - // | -1 0 | | 0 -1 | | -1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; - LOGD("Layer vertically reflected then rotated 270 degrees"); - } - } else { - if (rotation._12 < 0) { - // 270 degree rotation - // - // | 0 1 | - // | -1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_270; - LOGD("Layer rotated 270 degrees"); - } - else { - // Vertical reflection then 90 degree rotation - // - // | 0 1 | | -1 0 | = | 0 1 | - // | -1 0 | | 0 1 | | 1 0 | - // - // Same as horizontal reflection then 270 degree rotation - // - // | 0 -1 | | 1 0 | = | 0 1 | - // | 1 0 | | 0 -1 | | 1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; - LOGD("Layer horizontally reflected then rotated 270 degrees"); - } - } - } else if (rotation._11 < 0) { - if (rotation._22 > 0) { - // Horizontal reflection - // - // | -1 0 | - // | 0 1 | - // - hwcLayer.transform = HWC_TRANSFORM_FLIP_H; - LOGD("Layer rotated 180 degrees"); - } - else { - // 180 degree rotation - // - // | -1 0 | - // | 0 -1 | - // - // Same as horizontal and vertical reflection - // - // | -1 0 | | 1 0 | = | -1 0 | - // | 0 1 | | 0 -1 | | 0 -1 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_180; - LOGD("Layer rotated 180 degrees"); - } - } else { - if (rotation._22 < 0) { - // Vertical reflection - // - // | 1 0 | - // | 0 -1 | - // - hwcLayer.transform = HWC_TRANSFORM_FLIP_V; - LOGD("Layer rotated 180 degrees"); - } - else { - // No rotation or reflection - // - // | 1 0 | - // | 0 1 | - // - hwcLayer.transform = 0; - } - } - - const bool needsYFlip = state.OriginBottomLeft() ? true - : false; - - if (needsYFlip) { - // Invert vertical reflection flag if it was already set - hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; - } - hwc_region_t region; - if (visibleRegion.GetNumRects() > 1) { - mVisibleRegions.push_back(HwcUtils::RectVector()); - HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); - bool isVisible = false; - if(!HwcUtils::PrepareVisibleRegion(visibleRegion, - layerTransform, - layerBufferTransform, - clip, - bufferRect, - visibleRects, - isVisible)) { - LOGD("A region of layer is too small to be rendered by HWC"); - return false; - } - if (!isVisible) { - // Layer is not visible, no need to render it - return true; - } - region.numRects = visibleRects->size(); - region.rects = &((*visibleRects)[0]); - } else { - region.numRects = 1; - region.rects = &(hwcLayer.displayFrame); - } - hwcLayer.visibleRegionScreen = region; - } else { - hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; - ColorLayer* colorLayer = aLayer->AsColorLayer(); - if (colorLayer->GetColor().a < 1.0) { - LOGD("Color layer has semitransparency which is unsupported"); - return false; - } - hwcLayer.transform = colorLayer->GetColor().ToABGR(); - } - -#if ANDROID_VERSION >= 21 - if (aFindSidebandStreams && hwcLayer.compositionType == HWC_SIDEBAND) { - mCachedSidebandLayers.AppendElement(hwcLayer); - } -#endif - - mHwcLayerMap.AppendElement(static_cast<LayerComposite*>(aLayer->ImplData())); - mList->numHwLayers++; - return true; -} - - -#if ANDROID_VERSION >= 17 -bool -HwcComposer2D::TryHwComposition(nsScreenGonk* aScreen) -{ - DisplaySurface* dispSurface = aScreen->GetDisplaySurface(); - - if (!(dispSurface && dispSurface->lastHandle)) { - LOGD("H/W Composition failed. DispSurface not initialized."); - return false; - } - - // Add FB layer - int idx = mList->numHwLayers++; - if (idx >= mMaxLayerCount) { - if (!ReallocLayerList() || idx >= mMaxLayerCount) { - LOGE("TryHwComposition failed! Could not add FB layer"); - return false; - } - } - - Prepare(dispSurface->lastHandle, -1, aScreen); - - /* Possible composition paths, after hwc prepare: - 1. GPU Composition - 2. BLIT Composition - 3. Full OVERLAY Composition - 4. Partial OVERLAY Composition (GPU + OVERLAY) */ - - bool gpuComposite = false; - bool blitComposite = false; - bool overlayComposite = true; - - for (int j=0; j < idx; j++) { - if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER || - mList->hwLayers[j].compositionType == HWC_BLIT) { - // Full OVERLAY composition is not possible on this frame - // It is either GPU / BLIT / partial OVERLAY composition. - overlayComposite = false; - break; - } - } - - if (!overlayComposite) { - for (int k=0; k < idx; k++) { - switch (mList->hwLayers[k].compositionType) { - case HWC_FRAMEBUFFER: - gpuComposite = true; - break; - case HWC_BLIT: - blitComposite = true; - break; -#if ANDROID_VERSION >= 21 - case HWC_SIDEBAND: -#endif - case HWC_OVERLAY: { - // HWC will compose HWC_OVERLAY layers in partial - // Overlay Composition, set layer composition flag - // on mapped LayerComposite to skip GPU composition - mHwcLayerMap[k]->SetLayerComposited(true); - - uint8_t opacity = std::min(0xFF, (int)(mHwcLayerMap[k]->GetLayer()->GetEffectiveOpacity() * 256.0)); - if ((mList->hwLayers[k].hints & HWC_HINT_CLEAR_FB) && - (opacity == 0xFF)) { - // Clear visible rect on FB with transparent pixels. - hwc_rect_t r = mList->hwLayers[k].displayFrame; - mHwcLayerMap[k]->SetClearRect(nsIntRect(r.left, r.top, - r.right - r.left, - r.bottom - r.top)); - } - break; - } - default: - break; - } - } - - if (gpuComposite) { - // GPU or partial OVERLAY Composition - return false; - } else if (blitComposite) { - // BLIT Composition, flip DispSurface target - GetGonkDisplay()->UpdateDispSurface(aScreen->GetEGLDisplay(), aScreen->GetEGLSurface()); - DisplaySurface* dispSurface = aScreen->GetDisplaySurface(); - if (!dispSurface) { - LOGE("H/W Composition failed. NULL DispSurface."); - return false; - } - mList->hwLayers[idx].handle = dispSurface->lastHandle; - mList->hwLayers[idx].acquireFenceFd = dispSurface->GetPrevDispAcquireFd(); - } - } - - // BLIT or full OVERLAY Composition - return Commit(aScreen); -} - -bool -HwcComposer2D::Render(nsIWidget* aWidget) -{ - nsScreenGonk* screen = static_cast<nsWindow*>(aWidget)->GetScreen(); - - // HWC module does not exist or mList is not created yet. - if (!mHal->HasHwc() || !mList) { - return GetGonkDisplay()->SwapBuffers(screen->GetEGLDisplay(), screen->GetEGLSurface()); - } else if (!mList && !ReallocLayerList()) { - LOGE("Cannot realloc layer list"); - return false; - } - - DisplaySurface* dispSurface = screen->GetDisplaySurface(); - if (!dispSurface) { - LOGE("H/W Composition failed. DispSurface not initialized."); - return false; - } - - if (mPrepared) { - // No mHwc prepare, if already prepared in current draw cycle - mList->hwLayers[mList->numHwLayers - 1].handle = dispSurface->lastHandle; - mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = dispSurface->GetPrevDispAcquireFd(); - } else { - // Update screen rect to handle a case that TryRenderWithHwc() is not called. - mScreenRect = screen->GetNaturalBounds().ToUnknownRect(); - - mList->flags = HWC_GEOMETRY_CHANGED; - mList->numHwLayers = 2; - mList->hwLayers[0].hints = 0; - mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; - mList->hwLayers[0].flags = HWC_SKIP_LAYER; - mList->hwLayers[0].backgroundColor = {0}; - mList->hwLayers[0].acquireFenceFd = -1; - mList->hwLayers[0].releaseFenceFd = -1; - mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height}; - -#if ANDROID_VERSION >= 21 - // Prepare layers for sideband streams - const uint32_t len = mCachedSidebandLayers.Length(); - for (uint32_t i = 0; i < len; ++i) { - ++mList->numHwLayers; - mList->hwLayers[i+1] = mCachedSidebandLayers[i]; - } -#endif - Prepare(dispSurface->lastHandle, dispSurface->GetPrevDispAcquireFd(), screen); - } - - // GPU or partial HWC Composition - return Commit(screen); -} - -void -HwcComposer2D::Prepare(buffer_handle_t dispHandle, int fence, nsScreenGonk* screen) -{ - if (mPrepared) { - LOGE("Multiple hwc prepare calls!"); - } - hwc_rect_t dispRect = {0, 0, mScreenRect.width, mScreenRect.height}; - mHal->Prepare(mList, screen->GetDisplayType(), dispRect, dispHandle, fence); - mPrepared = true; -} - -bool -HwcComposer2D::Commit(nsScreenGonk* aScreen) -{ - for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { - mList->hwLayers[j].acquireFenceFd = -1; - if (mHwcLayerMap.IsEmpty() || - (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER)) { - continue; - } - LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState(); - if (!state.mTexture) { - continue; - } - FenceHandle fence = state.mTexture->GetAndResetAcquireFenceHandle(); - if (fence.IsValid()) { - RefPtr<FenceHandle::FdObj> fdObj = fence.GetAndResetFdObj(); - mList->hwLayers[j].acquireFenceFd = fdObj->GetAndResetFd(); - } - } - - int err = mHal->Set(mList, aScreen->GetDisplayType()); - - mPrevRetireFence.TransferToAnotherFenceHandle(mPrevDisplayFence); - - for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { - if (mList->hwLayers[j].releaseFenceFd >= 0) { - int fd = mList->hwLayers[j].releaseFenceFd; - mList->hwLayers[j].releaseFenceFd = -1; - RefPtr<FenceHandle::FdObj> fdObj = new FenceHandle::FdObj(fd); - FenceHandle fence(fdObj); - - LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState(); - if (!state.mTexture) { - continue; - } - state.mTexture->SetReleaseFenceHandle(fence); - } - } - - if (mList->retireFenceFd >= 0) { - mPrevRetireFence = FenceHandle(new FenceHandle::FdObj(mList->retireFenceFd)); - } - - // Set DisplaySurface layer fence - DisplaySurface* displaySurface = aScreen->GetDisplaySurface(); - displaySurface->setReleaseFenceFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd); - mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd = -1; - - mPrepared = false; - return !err; -} -#else -bool -HwcComposer2D::TryHwComposition(nsScreenGonk* aScreen) -{ - mHal->SetEGLInfo(aScreen->GetEGLDisplay(), aScreen->GetEGLSurface()); - return !mHal->Set(mList, aScreen->GetDisplayType()); -} - -bool -HwcComposer2D::Render(nsIWidget* aWidget) -{ - nsScreenGonk* screen = static_cast<nsWindow*>(aWidget)->GetScreen(); - return GetGonkDisplay()->SwapBuffers(screen->GetEGLDisplay(), screen->GetEGLSurface()); -} -#endif - -bool -HwcComposer2D::TryRenderWithHwc(Layer* aRoot, - nsIWidget* aWidget, - bool aGeometryChanged, - bool aHasImageHostOverlays) -{ - if (!mHal->HasHwc()) { - return false; - } - - nsScreenGonk* screen = static_cast<nsWindow*>(aWidget)->GetScreen(); - - if (mList) { - mList->flags = mHal->GetGeometryChangedFlag(aGeometryChanged); - mList->numHwLayers = 0; - mHwcLayerMap.Clear(); - } - - if (mPrepared) { - mHal->ResetHwc(); - mPrepared = false; - } - - // XXX: The clear() below means all rect vectors will be have to be - // reallocated. We may want to avoid this if possible - mVisibleRegions.clear(); - - mScreenRect = screen->GetNaturalBounds().ToUnknownRect(); - MOZ_ASSERT(mHwcLayerMap.IsEmpty()); - mCachedSidebandLayers.Clear(); - if (!PrepareLayerList(aRoot, - mScreenRect, - gfx::Matrix(), - /* aFindSidebandStreams */ false)) - { - mHwcLayerMap.Clear(); - LOGD("Render aborted. Fallback to GPU Composition"); - if (aHasImageHostOverlays) { - LOGD("Prepare layers of SidebandStreams"); - // Failed to create a layer list for hwc. But we need the list - // only for handling sideband streams. Traverse layer tree without - // some early returns to make sure we can find all the layers. - // It is the best wrong thing that we can do. - PrepareLayerList(aRoot, - mScreenRect, - gfx::Matrix(), - /* aFindSidebandStreams */ true); - // Reset mPrepared to false, since we already fell back to - // gpu composition. - mPrepared = false; - } - return false; - } - - // Send data to LayerScope for debugging - SendtoLayerScope(); - - if (!TryHwComposition(screen)) { - LOGD("Full HWC Composition failed. Fallback to GPU Composition or partial OVERLAY Composition"); - LayerScope::CleanLayer(); - return false; - } - - LOGD("Frame rendered"); - return true; -} - -void -HwcComposer2D::SendtoLayerScope() -{ - if (!LayerScope::CheckSendable()) { - return; - } - - const int len = mList->numHwLayers; - for (int i = 0; i < len; ++i) { - LayerComposite* layer = mHwcLayerMap[i]; - const hwc_rect_t r = mList->hwLayers[i].displayFrame; - LayerScope::SendLayer(layer, r.right - r.left, r.bottom - r.top); - } -} - -} // namespace mozilla diff --git a/widget/gonk/HwcComposer2D.h b/widget/gonk/HwcComposer2D.h deleted file mode 100644 index 56c1d1ec1..000000000 --- a/widget/gonk/HwcComposer2D.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2012, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcComposer2D -#define mozilla_HwcComposer2D - -#include "Composer2D.h" -#include "hwchal/HwcHALBase.h" // for HwcHAL -#include "HwcUtils.h" // for RectVector -#include "Layers.h" -#include "mozilla/Mutex.h" -#include "mozilla/layers/FenceUtils.h" // for FenceHandle -#include "mozilla/UniquePtr.h" // for HwcHAL - -#include <vector> -#include <list> - -#include <utils/Timers.h> - -class nsScreenGonk; - -namespace mozilla { - -namespace gl { - class GLContext; -} - -namespace layers { -class CompositorBridgeParent; -class Layer; -} - -/* - * HwcComposer2D provides a way for gecko to render frames - * using hwcomposer.h in the AOSP HAL. - * - * hwcomposer.h defines an interface for display composition - * using dedicated hardware. This hardware is usually faster - * or more power efficient than the GPU. However, in exchange - * for better performance, generality has to be sacrificed: - * no 3d transforms, no intermediate surfaces, no special shader effects, - * and loss of other goodies depending on the platform. - * - * In general, when hwc is enabled gecko tries to compose - * its frames using HwcComposer2D first. Then if HwcComposer2D is - * unable to compose a frame then it falls back to compose it - * using the GPU with OpenGL. - * - */ -class HwcComposer2D : public mozilla::layers::Composer2D { -public: - HwcComposer2D(); - virtual ~HwcComposer2D(); - - static HwcComposer2D* GetInstance(); - - // Returns TRUE if the container has been succesfully rendered - // Returns FALSE if the container cannot be fully rendered - // by this composer so nothing was rendered at all - virtual bool TryRenderWithHwc(layers::Layer* aRoot, - nsIWidget* aWidget, - bool aGeometryChanged, - bool aHasImageHostOverlays) override; - - virtual bool Render(nsIWidget* aWidget) override; - - virtual bool HasHwc() override { return mHal->HasHwc(); } - - bool EnableVsync(bool aEnable); - bool RegisterHwcEventCallback(); - void Vsync(int aDisplay, int64_t aTimestamp); - void Invalidate(); - void Hotplug(int aDisplay, int aConnected); - void SetCompositorBridgeParent(layers::CompositorBridgeParent* aCompositorBridgeParent); - -private: - void Reset(); - void Prepare(buffer_handle_t dispHandle, int fence, nsScreenGonk* screen); - bool Commit(nsScreenGonk* aScreen); - bool TryHwComposition(nsScreenGonk* aScreen); - bool ReallocLayerList(); - bool PrepareLayerList(layers::Layer* aContainer, const nsIntRect& aClip, - const gfx::Matrix& aParentTransform, - bool aFindSidebandStreams); - void SendtoLayerScope(); - - UniquePtr<HwcHALBase> mHal; - HwcList* mList; - nsIntRect mScreenRect; - int mMaxLayerCount; - bool mColorFill; - bool mRBSwapSupport; - //Holds all the dynamically allocated RectVectors needed - //to render the current frame - std::list<HwcUtils::RectVector> mVisibleRegions; - layers::FenceHandle mPrevRetireFence; - layers::FenceHandle mPrevDisplayFence; - nsTArray<HwcLayer> mCachedSidebandLayers; - nsTArray<layers::LayerComposite*> mHwcLayerMap; - bool mPrepared; - bool mHasHWVsync; - layers::CompositorBridgeParent* mCompositorBridgeParent; - Mutex mLock; -}; - -} // namespace mozilla - -#endif // mozilla_HwcComposer2D diff --git a/widget/gonk/HwcUtils.cpp b/widget/gonk/HwcUtils.cpp deleted file mode 100644 index a8f030f3c..000000000 --- a/widget/gonk/HwcUtils.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2013 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#include <android/log.h> -#include "HwcUtils.h" -#include "gfxUtils.h" -#include "gfx2DGlue.h" - -#define LOG_TAG "HwcUtils" - -#if (LOG_NDEBUG == 0) -#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args) -#else -#define LOGD(args...) ((void)0) -#endif - -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) - - -namespace mozilla { - -/* Utility functions for HwcComposer */ - - - -/* static */ bool -HwcUtils::PrepareLayerRects(nsIntRect aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - bool aYFlipped, - hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) { - - gfxMatrix aTransform = gfx::ThebesMatrix(aLayerTransform); - gfxRect visibleRect(ThebesRect(aVisible)); - gfxRect clip(ThebesRect(aClip)); - gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect); - // |clip| is guaranteed to be integer - visibleRectScreen.IntersectRect(visibleRectScreen, clip); - - if (visibleRectScreen.IsEmpty()) { - return false; - } - - gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform); - inverse.Invert(); - gfxRect crop = inverse.TransformBounds(visibleRectScreen); - - //clip to buffer size - crop.IntersectRect(crop, ThebesRect(aBufferRect)); - crop.Round(); - - if (crop.IsEmpty()) { - return false; - } - - //propagate buffer clipping back to visible rect - gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform); - visibleRectScreen = layerBufferTransform.TransformBounds(crop); - visibleRectScreen.Round(); - - // Map from layer space to buffer space - crop -= aBufferRect.TopLeft(); - if (aYFlipped) { - crop.y = aBufferRect.height - (crop.y + crop.height); - } - - aSourceCrop->left = crop.x; - aSourceCrop->top = crop.y; - aSourceCrop->right = crop.x + crop.width; - aSourceCrop->bottom = crop.y + crop.height; - - aVisibleRegionScreen->left = visibleRectScreen.x; - aVisibleRegionScreen->top = visibleRectScreen.y; - aVisibleRegionScreen->right = visibleRectScreen.x + visibleRectScreen.width; - aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height; - - return true; -} - -/* static */ bool -HwcUtils::PrepareVisibleRegion(const nsIntRegion& aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - RectVector* aVisibleRegionScreen, - bool& aIsVisible) { - const float MIN_SRC_WIDTH = 2.f; - const float MIN_SRC_HEIGHT = 2.f; - - gfxMatrix layerTransform = gfx::ThebesMatrix(aLayerTransform); - gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform); - gfxRect bufferRect = - layerBufferTransform.TransformBounds(ThebesRect(aBufferRect)); - gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform); - inverse.Invert(); - aIsVisible = false; - - for (auto iter = aVisible.RectIter(); !iter.Done(); iter.Next()) { - gfxRect screenRect = - layerTransform.TransformBounds(ThebesRect(iter.Get())); - screenRect.IntersectRect(screenRect, bufferRect); - screenRect.IntersectRect(screenRect, ThebesRect(aClip)); - screenRect.Round(); - if (screenRect.IsEmpty()) { - continue; - } - - hwc_rect_t visibleRectScreen; - visibleRectScreen.left = screenRect.x; - visibleRectScreen.top = screenRect.y; - visibleRectScreen.right = screenRect.XMost(); - visibleRectScreen.bottom = screenRect.YMost(); - - gfxRect srcCrop = inverse.TransformBounds(screenRect); - // When src crop is very small, HWC could not render correctly in some cases. - // See Bug 1169093 - if(srcCrop.Width() < MIN_SRC_WIDTH || srcCrop.Height() < MIN_SRC_HEIGHT) { - return false; - } - - aVisibleRegionScreen->push_back(visibleRectScreen); - aIsVisible = true; - } - - return true; -} - -/* static */ bool -HwcUtils::CalculateClipRect(const gfx::Matrix& transform, - const nsIntRect* aLayerClip, - nsIntRect aParentClip, nsIntRect* aRenderClip) { - - gfxMatrix aTransform = gfx::ThebesMatrix(transform); - *aRenderClip = aParentClip; - - if (!aLayerClip) { - return true; - } - - if (aLayerClip->IsEmpty()) { - return false; - } - - nsIntRect clip = *aLayerClip; - - gfxRect r = ThebesRect(clip); - gfxRect trClip = aTransform.TransformBounds(r); - trClip.Round(); - gfxUtils::GfxRectToIntRect(trClip, &clip); - - aRenderClip->IntersectRect(*aRenderClip, clip); - return true; -} - -} // namespace mozilla diff --git a/widget/gonk/HwcUtils.h b/widget/gonk/HwcUtils.h deleted file mode 100644 index 876ff8e99..000000000 --- a/widget/gonk/HwcUtils.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcUtils -#define mozilla_HwcUtils - -#include "Layers.h" -#include <vector> -#include "hardware/hwcomposer.h" - -namespace mozilla { - -namespace gfx { -class Matrix; -} - -class HwcUtils { -public: - -enum { - HWC_USE_GPU = HWC_FRAMEBUFFER, - HWC_USE_OVERLAY = HWC_OVERLAY, - HWC_USE_COPYBIT -}; - -// HWC layer flags -enum { - // Draw a solid color rectangle - // The color should be set on the transform member of the hwc_layer_t struct - // The expected format is a 32 bit ABGR with 8 bits per component - HWC_COLOR_FILL = 0x8, - // Swap the RB pixels of gralloc buffer, like RGBA<->BGRA or RGBX<->BGRX - // The flag will be set inside LayerRenderState - HWC_FORMAT_RB_SWAP = 0x40 -}; - -typedef std::vector<hwc_rect_t> RectVector; - -/* Utility functions - implemented in HwcUtils.cpp */ - -/** - * Calculates the layer's clipping rectangle - * - * @param aTransform Input. A transformation matrix - * It transforms the clip rect to screen space - * @param aLayerClip Input. The layer's internal clipping rectangle. - * This may be NULL which means the layer has no internal clipping - * The origin is the top-left corner of the layer - * @param aParentClip Input. The parent layer's rendering clipping rectangle - * The origin is the top-left corner of the screen - * @param aRenderClip Output. The layer's rendering clipping rectangle - * The origin is the top-left corner of the screen - * @return true if the layer should be rendered. - * false if the layer can be skipped - */ -static bool CalculateClipRect(const gfx::Matrix& aTransform, - const nsIntRect* aLayerClip, - nsIntRect aParentClip, nsIntRect* aRenderClip); - - -/** - * Prepares hwc layer visible region required for hwc composition - * - * @param aVisible Input. Layer's unclipped visible region - * The origin is the top-left corner of the layer - * @param aLayerTransform Input. Layer's transformation matrix - * It transforms from layer space to screen space - * @param aLayerBufferTransform Input. Layer buffer's transformation matrix - * It transforms from layer buffer's space to screen space - * @param aClip Input. A clipping rectangle. - * The origin is the top-left corner of the screen - * @param aBufferRect Input. The layer's buffer bounds - * The origin is the top-left corner of the layer - * @param aVisibleRegionScreen Output. Visible region in screen space. - * The origin is the top-left corner of the screen - * @param aIsVisible Output. true if region is visible - * false if region is not visible - * @return true if region can be rendered by HWC. - * false if region should not be rendered by HWC - */ -static bool PrepareVisibleRegion(const nsIntRegion& aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - RectVector* aVisibleRegionScreen, - bool& aIsVisible); - - -/** - * Sets hwc layer rectangles required for hwc composition - * - * @param aVisible Input. Layer's unclipped visible rectangle - * The origin is the top-left corner of the layer - * @param aLayerTransform Input. Layer's transformation matrix - * It transforms from layer space to screen space - * @param aLayerBufferTransform Input. Layer buffer's transformation matrix - * It transforms from layer buffer's space to screen space - * @param aClip Input. A clipping rectangle. - * The origin is the top-left corner of the screen - * @param aBufferRect Input. The layer's buffer bounds - * The origin is the top-left corner of the layer - * @param aYFlipped Input. true if the buffer is rendered as Y flipped - * @param aSurceCrop Output. Area of the source to consider, - * the origin is the top-left corner of the buffer - * @param aVisibleRegionScreen Output. Visible region in screen space. - * The origin is the top-left corner of the screen - * @return true if the layer should be rendered. - * false if the layer can be skipped - */ -static bool PrepareLayerRects(nsIntRect aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - bool aYFlipped, - hwc_rect_t* aSourceCrop, - hwc_rect_t* aVisibleRegionScreen); - -}; - -} // namespace mozilla - -#endif // mozilla_HwcUtils diff --git a/widget/gonk/OrientationObserver.cpp b/widget/gonk/OrientationObserver.cpp deleted file mode 100644 index 9096404cf..000000000 --- a/widget/gonk/OrientationObserver.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "base/basictypes.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/Hal.h" -#include "nsIScreen.h" -#include "nsIScreenManager.h" -#include "OrientationObserver.h" -#include "mozilla/HalSensor.h" -#include "ProcessOrientation.h" -#include "nsServiceManagerUtils.h" - -using namespace mozilla; -using namespace dom; - -namespace { - -struct OrientationMapping { - uint32_t mScreenRotation; - ScreenOrientationInternal mDomOrientation; -}; - -static OrientationMapping sOrientationMappings[] = { - {nsIScreen::ROTATION_0_DEG, eScreenOrientation_PortraitPrimary}, - {nsIScreen::ROTATION_180_DEG, eScreenOrientation_PortraitSecondary}, - {nsIScreen::ROTATION_90_DEG, eScreenOrientation_LandscapePrimary}, - {nsIScreen::ROTATION_270_DEG, eScreenOrientation_LandscapeSecondary}, -}; - -const static uint32_t sDefaultLandscape = 2; -const static uint32_t sDefaultPortrait = 0; - -static uint32_t sOrientationOffset = 0; - -static already_AddRefed<nsIScreen> -GetPrimaryScreen() -{ - nsCOMPtr<nsIScreenManager> screenMgr = - do_GetService("@mozilla.org/gfx/screenmanager;1"); - NS_ENSURE_TRUE(screenMgr, nullptr); - - nsCOMPtr<nsIScreen> screen; - screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); - return screen.forget(); -} - -static void -DetectDefaultOrientation() -{ - nsCOMPtr<nsIScreen> screen = GetPrimaryScreen(); - if (!screen) { - return; - } - - int32_t left, top, width, height; - if (NS_FAILED(screen->GetRect(&left, &top, &width, &height))) { - return; - } - - uint32_t rotation; - if (NS_FAILED(screen->GetRotation(&rotation))) { - return; - } - - if (width < height) { - if (rotation == nsIScreen::ROTATION_0_DEG || - rotation == nsIScreen::ROTATION_180_DEG) { - sOrientationOffset = sDefaultPortrait; - } else { - sOrientationOffset = sDefaultLandscape; - } - } else { - if (rotation == nsIScreen::ROTATION_0_DEG || - rotation == nsIScreen::ROTATION_180_DEG) { - sOrientationOffset = sDefaultLandscape; - } else { - sOrientationOffset = sDefaultPortrait; - } - } -} - -/** - * Converts DOM orientation to nsIScreen rotation. Portrait and Landscape are - * treated as PortraitPrimary and LandscapePrimary, respectively, during - * conversion. - * - * @param aOrientation DOM orientation e.g. - * dom::eScreenOrientation_PortraitPrimary. - * @param aResult output nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG. - * @return NS_OK on success. NS_ILLEGAL_VALUE on failure. - */ -static nsresult -ConvertToScreenRotation(ScreenOrientationInternal aOrientation, uint32_t *aResult) -{ - for (uint32_t i = 0; i < ArrayLength(sOrientationMappings); i++) { - if (aOrientation & sOrientationMappings[i].mDomOrientation) { - // Shift the mappings in sOrientationMappings so devices with default - // landscape orientation map landscape-primary to 0 degree and so forth. - int adjusted = (i + sOrientationOffset) % - ArrayLength(sOrientationMappings); - *aResult = sOrientationMappings[adjusted].mScreenRotation; - return NS_OK; - } - } - - *aResult = nsIScreen::ROTATION_0_DEG; - return NS_ERROR_ILLEGAL_VALUE; -} - -/** - * Converts nsIScreen rotation to DOM orientation. - * - * @param aRotation nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG. - * @param aResult output DOM orientation e.g. - * dom::eScreenOrientation_PortraitPrimary. - * @return NS_OK on success. NS_ILLEGAL_VALUE on failure. - */ -nsresult -ConvertToDomOrientation(uint32_t aRotation, ScreenOrientationInternal *aResult) -{ - for (uint32_t i = 0; i < ArrayLength(sOrientationMappings); i++) { - if (aRotation == sOrientationMappings[i].mScreenRotation) { - // Shift the mappings in sOrientationMappings so devices with default - // landscape orientation map 0 degree to landscape-primary and so forth. - int adjusted = (i + sOrientationOffset) % - ArrayLength(sOrientationMappings); - *aResult = sOrientationMappings[adjusted].mDomOrientation; - return NS_OK; - } - } - - *aResult = eScreenOrientation_None; - return NS_ERROR_ILLEGAL_VALUE; -} - -// Note that all operations with sOrientationSensorObserver -// should be on the main thread. -static StaticAutoPtr<OrientationObserver> sOrientationSensorObserver; - -} // namespace - -OrientationObserver* -OrientationObserver::GetInstance() -{ - if (!sOrientationSensorObserver) { - sOrientationSensorObserver = new OrientationObserver(); - ClearOnShutdown(&sOrientationSensorObserver); - } - - return sOrientationSensorObserver; -} - -OrientationObserver::OrientationObserver() - : mAutoOrientationEnabled(false) - , mAllowedOrientations(sDefaultOrientations) - , mOrientation(new mozilla::ProcessOrientation()) -{ - DetectDefaultOrientation(); - - EnableAutoOrientation(); -} - -OrientationObserver::~OrientationObserver() -{ - if (mAutoOrientationEnabled) { - DisableAutoOrientation(); - } -} - -/* static */ void -OrientationObserver::ShutDown() -{ - if (!sOrientationSensorObserver) { - return; - } - - if (sOrientationSensorObserver->mAutoOrientationEnabled) { - sOrientationSensorObserver->DisableAutoOrientation(); - } -} - -void -OrientationObserver::Notify(const hal::SensorData& aSensorData) -{ - // Sensor will call us on the main thread. - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aSensorData.sensor() == hal::SensorType::SENSOR_ACCELERATION); - - nsCOMPtr<nsIScreen> screen = GetPrimaryScreen(); - if (!screen) { - return; - } - - uint32_t currRotation; - if(NS_FAILED(screen->GetRotation(&currRotation))) { - return; - } - - int rotation = mOrientation->OnSensorChanged(aSensorData, static_cast<int>(currRotation)); - if (rotation < 0 || uint32_t(rotation) == currRotation) { - return; - } - - ScreenOrientationInternal orientation; - if (NS_FAILED(ConvertToDomOrientation(rotation, &orientation))) { - return; - } - - if ((mAllowedOrientations & orientation) == eScreenOrientation_None) { - // The orientation from sensor is not allowed. - return; - } - - if (NS_FAILED(screen->SetRotation(static_cast<uint32_t>(rotation)))) { - // Don't notify dom on rotation failure. - return; - } -} - -/** - * Register the observer. Note that the observer shouldn't be registered. - */ -void -OrientationObserver::EnableAutoOrientation() -{ - MOZ_ASSERT(NS_IsMainThread() && !mAutoOrientationEnabled); - - mOrientation->Reset(); - hal::RegisterSensorObserver(hal::SENSOR_ACCELERATION, this); - mAutoOrientationEnabled = true; -} - -/** - * Unregister the observer. Note that the observer should already be registered. - */ -void -OrientationObserver::DisableAutoOrientation() -{ - MOZ_ASSERT(NS_IsMainThread() && mAutoOrientationEnabled); - - hal::UnregisterSensorObserver(hal::SENSOR_ACCELERATION, this); - mAutoOrientationEnabled = false; -} - -bool -OrientationObserver::LockScreenOrientation(ScreenOrientationInternal aOrientation) -{ - MOZ_ASSERT(aOrientation | (eScreenOrientation_PortraitPrimary | - eScreenOrientation_PortraitSecondary | - eScreenOrientation_LandscapePrimary | - eScreenOrientation_LandscapeSecondary | - eScreenOrientation_Default)); - - if (aOrientation == eScreenOrientation_Default) { - aOrientation = (sOrientationOffset == sDefaultPortrait) ? - eScreenOrientation_PortraitPrimary : - eScreenOrientation_LandscapePrimary; - } - - // If there are multiple orientations allowed, we should enable the - // auto-rotation. - if (aOrientation != eScreenOrientation_LandscapePrimary && - aOrientation != eScreenOrientation_LandscapeSecondary && - aOrientation != eScreenOrientation_PortraitPrimary && - aOrientation != eScreenOrientation_PortraitSecondary) { - if (!mAutoOrientationEnabled) { - EnableAutoOrientation(); - } - } else if (mAutoOrientationEnabled) { - DisableAutoOrientation(); - } - - mAllowedOrientations = aOrientation; - - nsCOMPtr<nsIScreen> screen = GetPrimaryScreen(); - NS_ENSURE_TRUE(screen, false); - - uint32_t currRotation; - nsresult rv = screen->GetRotation(&currRotation); - NS_ENSURE_SUCCESS(rv, false); - - ScreenOrientationInternal currOrientation = eScreenOrientation_None; - rv = ConvertToDomOrientation(currRotation, &currOrientation); - NS_ENSURE_SUCCESS(rv, false); - - // Don't rotate if the current orientation matches one of the - // requested orientations. - if (currOrientation & aOrientation) { - return true; - } - - // Return false on invalid orientation value. - uint32_t rotation; - rv = ConvertToScreenRotation(aOrientation, &rotation); - NS_ENSURE_SUCCESS(rv, false); - - rv = screen->SetRotation(rotation); - NS_ENSURE_SUCCESS(rv, false); - - // This conversion will disambiguate aOrientation. - ScreenOrientationInternal orientation; - rv = ConvertToDomOrientation(rotation, &orientation); - NS_ENSURE_SUCCESS(rv, false); - - return true; -} - -void -OrientationObserver::UnlockScreenOrientation() -{ - if (!mAutoOrientationEnabled) { - EnableAutoOrientation(); - } - - mAllowedOrientations = sDefaultOrientations; -} diff --git a/widget/gonk/OrientationObserver.h b/widget/gonk/OrientationObserver.h deleted file mode 100644 index c841ea878..000000000 --- a/widget/gonk/OrientationObserver.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef OrientationObserver_h -#define OrientationObserver_h - -#include "mozilla/Observer.h" -#include "mozilla/dom/ScreenOrientation.h" -#include "mozilla/UniquePtr.h" - -namespace mozilla { -class ProcessOrientation; -namespace hal { -class SensorData; -typedef mozilla::Observer<SensorData> ISensorObserver; -} // namespace hal -} // namespace mozilla - -using mozilla::hal::ISensorObserver; -using mozilla::hal::SensorData; -using mozilla::dom::ScreenOrientationInternal; - -class OrientationObserver : public ISensorObserver { -public: - OrientationObserver(); - ~OrientationObserver(); - - // Call DisableAutoOrientation on the existing OrientatiOnobserver singleton, - // if it exists. If no OrientationObserver exists, do nothing. - static void ShutDown(); - - // Notification from sensor. - void Notify(const SensorData& aSensorData); - - // Methods to enable/disable automatic orientation. - void EnableAutoOrientation(); - void DisableAutoOrientation(); - - // Methods called by methods in hal_impl namespace. - bool LockScreenOrientation(ScreenOrientationInternal aOrientation); - void UnlockScreenOrientation(); - - static OrientationObserver* GetInstance(); - -private: - bool mAutoOrientationEnabled; - uint32_t mAllowedOrientations; - mozilla::UniquePtr<mozilla::ProcessOrientation> mOrientation; - - static const uint32_t sDefaultOrientations = - mozilla::dom::eScreenOrientation_PortraitPrimary | - mozilla::dom::eScreenOrientation_PortraitSecondary | - mozilla::dom::eScreenOrientation_LandscapePrimary | - mozilla::dom::eScreenOrientation_LandscapeSecondary; -}; - -#endif diff --git a/widget/gonk/ProcessOrientation.cpp b/widget/gonk/ProcessOrientation.cpp deleted file mode 100644 index bbdcface8..000000000 --- a/widget/gonk/ProcessOrientation.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (c) 2013, Linux Foundation. All rights reserved - * - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#include "base/basictypes.h" -#include "mozilla/Hal.h" -#include "mozilla/Unused.h" -#include "nsIScreen.h" -#include "nsIScreenManager.h" -#include "OrientationObserver.h" -#include "ProcessOrientation.h" -#include "mozilla/HalSensor.h" -#include "math.h" -#include "limits.h" -#include "android/log.h" - -#if 0 -#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, "ProcessOrientation" , ## args) -#else -#define LOGD(args...) -#endif - -namespace mozilla { - -// We work with all angles in degrees in this class. -#define RADIANS_TO_DEGREES (180/M_PI) - -// Number of nanoseconds per millisecond. -#define NANOS_PER_MS 1000000 - -// Indices into SensorEvent.values for the accelerometer sensor. -#define ACCELEROMETER_DATA_X 0 -#define ACCELEROMETER_DATA_Y 1 -#define ACCELEROMETER_DATA_Z 2 - -// The minimum amount of time that a predicted rotation must be stable before -// it is accepted as a valid rotation proposal. This value can be quite small -// because the low-pass filter already suppresses most of the noise so we're -// really just looking for quick confirmation that the last few samples are in -// agreement as to the desired orientation. -#define PROPOSAL_SETTLE_TIME_NANOS (40*NANOS_PER_MS) - -// The minimum amount of time that must have elapsed since the device last -// exited the flat state (time since it was picked up) before the proposed -// rotation can change. -#define PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS (500*NANOS_PER_MS) - -// The minimum amount of time that must have elapsed since the device stopped -// swinging (time since device appeared to be in the process of being put down -// or put away into a pocket) before the proposed rotation can change. -#define PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS (300*NANOS_PER_MS) - -// The minimum amount of time that must have elapsed since the device stopped -// undergoing external acceleration before the proposed rotation can change. -#define PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS (500*NANOS_PER_MS) - -// If the tilt angle remains greater than the specified angle for a minimum of -// the specified time, then the device is deemed to be lying flat -// (just chillin' on a table). -#define FLAT_ANGLE 75 -#define FLAT_TIME_NANOS (1000*NANOS_PER_MS) - -// If the tilt angle has increased by at least delta degrees within the -// specified amount of time, then the device is deemed to be swinging away -// from the user down towards flat (tilt = 90). -#define SWING_AWAY_ANGLE_DELTA 20 -#define SWING_TIME_NANOS (300*NANOS_PER_MS) - -// The maximum sample inter-arrival time in milliseconds. If the acceleration -// samples are further apart than this amount in time, we reset the state of -// the low-pass filter and orientation properties. This helps to handle -// boundary conditions when the device is turned on, wakes from suspend or -// there is a significant gap in samples. -#define MAX_FILTER_DELTA_TIME_NANOS (1000*NANOS_PER_MS) - -// The acceleration filter time constant. -// -// This time constant is used to tune the acceleration filter such that -// impulses and vibrational noise (think car dock) is suppressed before we try -// to calculate the tilt and orientation angles. -// -// The filter time constant is related to the filter cutoff frequency, which -// is the frequency at which signals are attenuated by 3dB (half the passband -// power). Each successive octave beyond this frequency is attenuated by an -// additional 6dB. -// -// Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz -// is given by Fc = 1 / (2pi * t). -// -// The higher the time constant, the lower the cutoff frequency, so more noise -// will be suppressed. -// -// Filtering adds latency proportional the time constant (inversely -// proportional to the cutoff frequency) so we don't want to make the time -// constant too large or we can lose responsiveness. Likewise we don't want -// to make it too small or we do a poor job suppressing acceleration spikes. -// Empirically, 100ms seems to be too small and 500ms is too large. Android -// default is 200. -#define FILTER_TIME_CONSTANT_MS 200.0f - -// State for orientation detection. Thresholds for minimum and maximum -// allowable deviation from gravity. -// -// If the device is undergoing external acceleration (being bumped, in a car -// that is turning around a corner or a plane taking off) then the magnitude -// may be substantially more or less than gravity. This can skew our -// orientation detection by making us think that up is pointed in a different -// direction. -// -// Conversely, if the device is in freefall, then there will be no gravity to -// measure at all. This is problematic because we cannot detect the orientation -// without gravity to tell us which way is up. A magnitude near 0 produces -// singularities in the tilt and orientation calculations. -// -// In both cases, we postpone choosing an orientation. -// -// However, we need to tolerate some acceleration because the angular momentum -// of turning the device can skew the observed acceleration for a short period -// of time. -#define NEAR_ZERO_MAGNITUDE 1 // m/s^2 -#define ACCELERATION_TOLERANCE 4 // m/s^2 -#define STANDARD_GRAVITY 9.80665f -#define MIN_ACCELERATION_MAGNITUDE (STANDARD_GRAVITY-ACCELERATION_TOLERANCE) -#define MAX_ACCELERATION_MAGNITUDE (STANDARD_GRAVITY+ACCELERATION_TOLERANCE) - -// Maximum absolute tilt angle at which to consider orientation data. Beyond -// this (i.e. when screen is facing the sky or ground), we completely ignore -// orientation data. -#define MAX_TILT 75 - -// The gap angle in degrees between adjacent orientation angles for -// hysteresis.This creates a "dead zone" between the current orientation and a -// proposed adjacent orientation. No orientation proposal is made when the -// orientation angle is within the gap between the current orientation and the -// adjacent orientation. -#define ADJACENT_ORIENTATION_ANGLE_GAP 45 - -const int -ProcessOrientation::tiltTolerance[][4] = { - {-25, 70}, // ROTATION_0 - {-25, 65}, // ROTATION_90 - {-25, 60}, // ROTATION_180 - {-25, 65} // ROTATION_270 -}; - -int -ProcessOrientation::GetProposedRotation() -{ - return mProposedRotation; -} - -int -ProcessOrientation::OnSensorChanged(const SensorData& event, - int deviceCurrentRotation) -{ - // The vector given in the SensorEvent points straight up (towards the sky) - // under ideal conditions (the phone is not accelerating). I'll call this up - // vector elsewhere. - const InfallibleTArray<float>& values = event.values(); - float x = values[ACCELEROMETER_DATA_X]; - float y = values[ACCELEROMETER_DATA_Y]; - float z = values[ACCELEROMETER_DATA_Z]; - - LOGD - ("ProcessOrientation: Raw acceleration vector: x = %f, y = %f, z = %f," - "magnitude = %f\n", x, y, z, sqrt(x * x + y * y + z * z)); - // Apply a low-pass filter to the acceleration up vector in cartesian space. - // Reset the orientation listener state if the samples are too far apart in - // time or when we see values of (0, 0, 0) which indicates that we polled the - // accelerometer too soon after turning it on and we don't have any data yet. - const int64_t now = (int64_t) event.timestamp(); - const int64_t then = mLastFilteredTimestampNanos; - const float timeDeltaMS = (now - then) * 0.000001f; - bool skipSample = false; - if (now < then - || now > then + MAX_FILTER_DELTA_TIME_NANOS - || (x == 0 && y == 0 && z == 0)) { - LOGD - ("ProcessOrientation: Resetting orientation listener."); - Reset(); - skipSample = true; - } else { - const float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS); - x = alpha * (x - mLastFilteredX) + mLastFilteredX; - y = alpha * (y - mLastFilteredY) + mLastFilteredY; - z = alpha * (z - mLastFilteredZ) + mLastFilteredZ; - LOGD - ("ProcessOrientation: Filtered acceleration vector: x=%f, y=%f, z=%f," - "magnitude=%f", z, y, z, sqrt(x * x + y * y + z * z)); - skipSample = false; - } - mLastFilteredTimestampNanos = now; - mLastFilteredX = x; - mLastFilteredY = y; - mLastFilteredZ = z; - - bool isAccelerating = false; - bool isFlat = false; - bool isSwinging = false; - if (skipSample) { - return -1; - } - - // Calculate the magnitude of the acceleration vector. - const float magnitude = sqrt(x * x + y * y + z * z); - if (magnitude < NEAR_ZERO_MAGNITUDE) { - LOGD - ("ProcessOrientation: Ignoring sensor data, magnitude too close to" - " zero."); - ClearPredictedRotation(); - } else { - // Determine whether the device appears to be undergoing external - // acceleration. - if (this->IsAccelerating(magnitude)) { - isAccelerating = true; - mAccelerationTimestampNanos = now; - } - // Calculate the tilt angle. This is the angle between the up vector and - // the x-y plane (the plane of the screen) in a range of [-90, 90] - // degrees. - // -90 degrees: screen horizontal and facing the ground (overhead) - // 0 degrees: screen vertical - // 90 degrees: screen horizontal and facing the sky (on table) - const int tiltAngle = - static_cast<int>(roundf(asin(z / magnitude) * RADIANS_TO_DEGREES)); - AddTiltHistoryEntry(now, tiltAngle); - - // Determine whether the device appears to be flat or swinging. - if (this->IsFlat(now)) { - isFlat = true; - mFlatTimestampNanos = now; - } - if (this->IsSwinging(now, tiltAngle)) { - isSwinging = true; - mSwingTimestampNanos = now; - } - // If the tilt angle is too close to horizontal then we cannot determine - // the orientation angle of the screen. - if (abs(tiltAngle) > MAX_TILT) { - LOGD - ("ProcessOrientation: Ignoring sensor data, tilt angle too high:" - " tiltAngle=%d", tiltAngle); - ClearPredictedRotation(); - } else { - // Calculate the orientation angle. - // This is the angle between the x-y projection of the up vector onto - // the +y-axis, increasing clockwise in a range of [0, 360] degrees. - int orientationAngle = - static_cast<int>(roundf(-atan2f(-x, y) * RADIANS_TO_DEGREES)); - if (orientationAngle < 0) { - // atan2 returns [-180, 180]; normalize to [0, 360] - orientationAngle += 360; - } - // Find the nearest rotation. - int nearestRotation = (orientationAngle + 45) / 90; - if (nearestRotation == 4) { - nearestRotation = 0; - } - // Determine the predicted orientation. - if (IsTiltAngleAcceptable(nearestRotation, tiltAngle) - && - IsOrientationAngleAcceptable - (nearestRotation, orientationAngle, deviceCurrentRotation)) { - UpdatePredictedRotation(now, nearestRotation); - LOGD - ("ProcessOrientation: Predicted: tiltAngle=%d, orientationAngle=%d," - " predictedRotation=%d, predictedRotationAgeMS=%f", - tiltAngle, - orientationAngle, - mPredictedRotation, - ((now - mPredictedRotationTimestampNanos) * 0.000001f)); - } else { - LOGD - ("ProcessOrientation: Ignoring sensor data, no predicted rotation:" - " tiltAngle=%d, orientationAngle=%d", - tiltAngle, - orientationAngle); - ClearPredictedRotation(); - } - } - } - - // Determine new proposed rotation. - const int oldProposedRotation = mProposedRotation; - if (mPredictedRotation < 0 || IsPredictedRotationAcceptable(now)) { - mProposedRotation = mPredictedRotation; - } - // Write final statistics about where we are in the orientation detection - // process. - LOGD - ("ProcessOrientation: Result: oldProposedRotation=%d,currentRotation=%d, " - "proposedRotation=%d, predictedRotation=%d, timeDeltaMS=%f, " - "isAccelerating=%d, isFlat=%d, isSwinging=%d, timeUntilSettledMS=%f, " - "timeUntilAccelerationDelayExpiredMS=%f, timeUntilFlatDelayExpiredMS=%f, " - "timeUntilSwingDelayExpiredMS=%f", - oldProposedRotation, - deviceCurrentRotation, mProposedRotation, - mPredictedRotation, timeDeltaMS, isAccelerating, isFlat, - isSwinging, RemainingMS(now, - mPredictedRotationTimestampNanos + - PROPOSAL_SETTLE_TIME_NANOS), - RemainingMS(now, - mAccelerationTimestampNanos + - PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS), - RemainingMS(now, - mFlatTimestampNanos + - PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS), - RemainingMS(now, - mSwingTimestampNanos + - PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS)); - - // Avoid unused-but-set compile warnings for these variables, when LOGD is - // a no-op, as it is by default: - Unused << isAccelerating; - Unused << isFlat; - Unused << isSwinging; - - // Tell the listener. - if (mProposedRotation != oldProposedRotation && mProposedRotation >= 0) { - LOGD - ("ProcessOrientation: Proposed rotation changed! proposedRotation=%d, " - "oldProposedRotation=%d", - mProposedRotation, - oldProposedRotation); - return mProposedRotation; - } - // Don't rotate screen - return -1; -} - -bool -ProcessOrientation::IsTiltAngleAcceptable(int rotation, int tiltAngle) -{ - return (tiltAngle >= tiltTolerance[rotation][0] - && tiltAngle <= tiltTolerance[rotation][1]); -} - -bool -ProcessOrientation::IsOrientationAngleAcceptable(int rotation, - int orientationAngle, - int currentRotation) -{ - // If there is no current rotation, then there is no gap. - // The gap is used only to introduce hysteresis among advertised orientation - // changes to avoid flapping. - if (currentRotation < 0) { - return true; - } - // If the specified rotation is the same or is counter-clockwise adjacent - // to the current rotation, then we set a lower bound on the orientation - // angle. For example, if currentRotation is ROTATION_0 and proposed is - // ROTATION_90, then we want to check orientationAngle > 45 + GAP / 2. - if (rotation == currentRotation || rotation == (currentRotation + 1) % 4) { - int lowerBound = rotation * 90 - 45 + ADJACENT_ORIENTATION_ANGLE_GAP / 2; - if (rotation == 0) { - if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) { - return false; - } - } else { - if (orientationAngle < lowerBound) { - return false; - } - } - } - // If the specified rotation is the same or is clockwise adjacent, then we - // set an upper bound on the orientation angle. For example, if - // currentRotation is ROTATION_0 and rotation is ROTATION_270, then we want - // to check orientationAngle < 315 - GAP / 2. - if (rotation == currentRotation || rotation == (currentRotation + 3) % 4) { - int upperBound = rotation * 90 + 45 - ADJACENT_ORIENTATION_ANGLE_GAP / 2; - if (rotation == 0) { - if (orientationAngle <= 45 && orientationAngle > upperBound) { - return false; - } - } else { - if (orientationAngle > upperBound) { - return false; - } - } - } - return true; -} - -bool -ProcessOrientation::IsPredictedRotationAcceptable(int64_t now) -{ - // The predicted rotation must have settled long enough. - if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) { - return false; - } - // The last flat state (time since picked up) must have been sufficiently long - // ago. - if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) { - return false; - } - // The last swing state (time since last movement to put down) must have been - // sufficiently long ago. - if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) { - return false; - } - // The last acceleration state must have been sufficiently long ago. - if (now < mAccelerationTimestampNanos - + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) { - return false; - } - // Looks good! - return true; -} - -int -ProcessOrientation::Reset() -{ - mLastFilteredTimestampNanos = std::numeric_limits<int64_t>::min(); - mProposedRotation = -1; - mFlatTimestampNanos = std::numeric_limits<int64_t>::min(); - mSwingTimestampNanos = std::numeric_limits<int64_t>::min(); - mAccelerationTimestampNanos = std::numeric_limits<int64_t>::min(); - ClearPredictedRotation(); - ClearTiltHistory(); - return -1; -} - -void -ProcessOrientation::ClearPredictedRotation() -{ - mPredictedRotation = -1; - mPredictedRotationTimestampNanos = std::numeric_limits<int64_t>::min(); -} - -void -ProcessOrientation::UpdatePredictedRotation(int64_t now, int rotation) -{ - if (mPredictedRotation != rotation) { - mPredictedRotation = rotation; - mPredictedRotationTimestampNanos = now; - } -} - -bool -ProcessOrientation::IsAccelerating(float magnitude) -{ - return magnitude < MIN_ACCELERATION_MAGNITUDE - || magnitude > MAX_ACCELERATION_MAGNITUDE; -} - -void -ProcessOrientation::ClearTiltHistory() -{ - mTiltHistory.history[0].timestampNanos = std::numeric_limits<int64_t>::min(); - mTiltHistory.index = 1; -} - -void -ProcessOrientation::AddTiltHistoryEntry(int64_t now, float tilt) -{ - mTiltHistory.history[mTiltHistory.index].tiltAngle = tilt; - mTiltHistory.history[mTiltHistory.index].timestampNanos = now; - mTiltHistory.index = (mTiltHistory.index + 1) % TILT_HISTORY_SIZE; - mTiltHistory.history[mTiltHistory.index].timestampNanos = std::numeric_limits<int64_t>::min(); -} - -bool -ProcessOrientation::IsFlat(int64_t now) -{ - for (int i = mTiltHistory.index; (i = NextTiltHistoryIndex(i)) >= 0;) { - if (mTiltHistory.history[i].tiltAngle < FLAT_ANGLE) { - break; - } - if (mTiltHistory.history[i].timestampNanos + FLAT_TIME_NANOS <= now) { - // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS. - return true; - } - } - return false; -} - -bool -ProcessOrientation::IsSwinging(int64_t now, float tilt) -{ - for (int i = mTiltHistory.index; (i = NextTiltHistoryIndex(i)) >= 0;) { - if (mTiltHistory.history[i].timestampNanos + SWING_TIME_NANOS < now) { - break; - } - if (mTiltHistory.history[i].tiltAngle + SWING_AWAY_ANGLE_DELTA <= tilt) { - // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS. - return true; - } - } - return false; -} - -int -ProcessOrientation::NextTiltHistoryIndex(int index) -{ - index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1; - return mTiltHistory.history[index].timestampNanos != std::numeric_limits<int64_t>::min() ? index : -1; -} - -float -ProcessOrientation::RemainingMS(int64_t now, int64_t until) -{ - return now >= until ? 0 : (until - now) * 0.000001f; -} - -} // namespace mozilla diff --git a/widget/gonk/ProcessOrientation.h b/widget/gonk/ProcessOrientation.h deleted file mode 100644 index d6d4bc3b6..000000000 --- a/widget/gonk/ProcessOrientation.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2013, Linux Foundation. All rights reserved - * - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#ifndef ProcessOrientation_h -#define ProcessOrientation_h - -#include "mozilla/Hal.h" - -namespace mozilla { - -// History of observed tilt angles. -#define TILT_HISTORY_SIZE 40 - -class ProcessOrientation { -public: - ProcessOrientation() {}; - ~ProcessOrientation() {}; - - int OnSensorChanged(const mozilla::hal::SensorData& event, int deviceCurrentRotation); - int Reset(); - -private: - int GetProposedRotation(); - - // Returns true if the tilt angle is acceptable for a given predicted - // rotation. - bool IsTiltAngleAcceptable(int rotation, int tiltAngle); - - // Returns true if the orientation angle is acceptable for a given predicted - // rotation. This function takes into account the gap between adjacent - // orientations for hysteresis. - bool IsOrientationAngleAcceptable(int rotation, int orientationAngle, - int currentRotation); - - // Returns true if the predicted rotation is ready to be advertised as a - // proposed rotation. - bool IsPredictedRotationAcceptable(int64_t now); - - void ClearPredictedRotation(); - void UpdatePredictedRotation(int64_t now, int rotation); - bool IsAccelerating(float magnitude); - void ClearTiltHistory(); - void AddTiltHistoryEntry(int64_t now, float tilt); - bool IsFlat(int64_t now); - bool IsSwinging(int64_t now, float tilt); - int NextTiltHistoryIndex(int index); - float RemainingMS(int64_t now, int64_t until); - - // The tilt angle range in degrees for each orientation. Beyond these tilt - // angles, we don't even consider transitioning into the specified orientation. - // We place more stringent requirements on unnatural orientations than natural - // ones to make it less likely to accidentally transition into those states. - // The first value of each pair is negative so it applies a limit when the - // device is facing down (overhead reading in bed). The second value of each - // pair is positive so it applies a limit when the device is facing up - // (resting on a table). The ideal tilt angle is 0 (when the device is vertical) - // so the limits establish how close to vertical the device must be in order - // to change orientation. - static const int tiltTolerance[][4]; - - // Timestamp and value of the last accelerometer sample. - int64_t mLastFilteredTimestampNanos; - float mLastFilteredX, mLastFilteredY, mLastFilteredZ; - - // The last proposed rotation, -1 if unknown. - int mProposedRotation; - - // Value of the current predicted rotation, -1 if unknown. - int mPredictedRotation; - - // Timestamp of when the predicted rotation most recently changed. - int64_t mPredictedRotationTimestampNanos; - - // Timestamp when the device last appeared to be flat for sure (the flat delay - // elapsed). - int64_t mFlatTimestampNanos; - - // Timestamp when the device last appeared to be swinging. - int64_t mSwingTimestampNanos; - - // Timestamp when the device last appeared to be undergoing external - // acceleration. - int64_t mAccelerationTimestampNanos; - - struct { - struct { - float tiltAngle; - int64_t timestampNanos; - } history[TILT_HISTORY_SIZE]; - int index; - } mTiltHistory; -}; - -} // namespace mozilla - -#endif diff --git a/widget/gonk/WidgetTraceEvent.cpp b/widget/gonk/WidgetTraceEvent.cpp deleted file mode 100644 index 558d9313e..000000000 --- a/widget/gonk/WidgetTraceEvent.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* 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 "mozilla/WidgetTraceEvent.h" -#include "mozilla/StaticPtr.h" -#include "nsThreadUtils.h" -#include <mozilla/CondVar.h> -#include <mozilla/Mutex.h> - -using mozilla::CondVar; -using mozilla::Mutex; -using mozilla::MutexAutoLock; - -namespace mozilla { - class TracerRunnable : public Runnable { - public: - TracerRunnable() { - mTracerLock = new Mutex("TracerRunnable"); - mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable"); - mMainThread = do_GetMainThread(); - } - - ~TracerRunnable() { - delete mTracerCondVar; - delete mTracerLock; - mTracerLock = nullptr; - mTracerCondVar = nullptr; - } - - virtual nsresult Run() { - MutexAutoLock lock(*mTracerLock); - mHasRun = true; - mTracerCondVar->Notify(); - return NS_OK; - } - - bool Fire() { - if (!mTracerLock || !mTracerCondVar) { - return false; - } - - MutexAutoLock lock(*mTracerLock); - mHasRun = false; - mMainThread->Dispatch(this, NS_DISPATCH_NORMAL); - while (!mHasRun) { - mTracerCondVar->Wait(); - } - return true; - } - - void Signal() { - MutexAutoLock lock(*mTracerLock); - mHasRun = true; - mTracerCondVar->Notify(); - } - - private: - Mutex* mTracerLock; - CondVar* mTracerCondVar; - bool mHasRun; - nsCOMPtr<nsIThread> mMainThread; - }; - - StaticRefPtr<TracerRunnable> sTracerRunnable; - - bool InitWidgetTracing() - { - if (!sTracerRunnable) { - sTracerRunnable = new TracerRunnable(); - } - return true; - } - - void CleanUpWidgetTracing() - { - sTracerRunnable = nullptr; - } - - bool FireAndWaitForTracerEvent() - { - if (sTracerRunnable) { - return sTracerRunnable->Fire(); - } - - return false; - } - - void SignalTracerThread() - { - if (sTracerRunnable) { - return sTracerRunnable->Signal(); - } - } -} // namespace mozilla - diff --git a/widget/gonk/hwchal/HwcHAL.cpp b/widget/gonk/hwchal/HwcHAL.cpp deleted file mode 100644 index 1793b75e6..000000000 --- a/widget/gonk/hwchal/HwcHAL.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#include "HwcHAL.h" -#include "libdisplay/GonkDisplay.h" -#include "mozilla/Assertions.h" - -namespace mozilla { - -HwcHAL::HwcHAL() - : HwcHALBase() -{ - // Some HALs don't want to open hwc twice. - // If GetDisplay already load hwc module, we don't need to load again - mHwc = (HwcDevice*)GetGonkDisplay()->GetHWCDevice(); - if (!mHwc) { - printf_stderr("HwcHAL Error: Cannot load hwcomposer"); - return; - } -} - -HwcHAL::~HwcHAL() -{ - mHwc = nullptr; -} - -bool -HwcHAL::Query(QueryType aType) -{ - if (!mHwc || !mHwc->query) { - return false; - } - - bool value = false; - int supported = 0; - if (mHwc->query(mHwc, static_cast<int>(aType), &supported) == 0/*android::NO_ERROR*/) { - value = !!supported; - } - return value; -} - -int -HwcHAL::Set(HwcList *aList, - uint32_t aDisp) -{ - MOZ_ASSERT(mHwc); - if (!mHwc) { - return -1; - } - - HwcList *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; - displays[aDisp] = aList; - return mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); -} - -int -HwcHAL::ResetHwc() -{ - return Set(nullptr, HWC_DISPLAY_PRIMARY); -} - -int -HwcHAL::Prepare(HwcList *aList, - uint32_t aDisp, - hwc_rect_t aDispRect, - buffer_handle_t aHandle, - int aFenceFd) -{ - MOZ_ASSERT(mHwc); - if (!mHwc) { - printf_stderr("HwcHAL Error: HwcDevice doesn't exist. A fence might be leaked."); - return -1; - } - - HwcList *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; - displays[aDisp] = aList; -#if ANDROID_VERSION >= 18 - aList->outbufAcquireFenceFd = -1; - aList->outbuf = nullptr; -#endif - aList->retireFenceFd = -1; - - const auto idx = aList->numHwLayers - 1; - aList->hwLayers[idx].hints = 0; - aList->hwLayers[idx].flags = 0; - aList->hwLayers[idx].transform = 0; - aList->hwLayers[idx].handle = aHandle; - aList->hwLayers[idx].blending = HWC_BLENDING_PREMULT; - aList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET; - SetCrop(aList->hwLayers[idx], aDispRect); - aList->hwLayers[idx].displayFrame = aDispRect; - aList->hwLayers[idx].visibleRegionScreen.numRects = 1; - aList->hwLayers[idx].visibleRegionScreen.rects = &aList->hwLayers[idx].displayFrame; - aList->hwLayers[idx].acquireFenceFd = aFenceFd; - aList->hwLayers[idx].releaseFenceFd = -1; -#if ANDROID_VERSION >= 18 - aList->hwLayers[idx].planeAlpha = 0xFF; -#endif - return mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); -} - -bool -HwcHAL::SupportTransparency() const -{ -#if ANDROID_VERSION >= 18 - return true; -#endif - return false; -} - -uint32_t -HwcHAL::GetGeometryChangedFlag(bool aGeometryChanged) const -{ -#if ANDROID_VERSION >= 19 - return aGeometryChanged ? HWC_GEOMETRY_CHANGED : 0; -#else - return HWC_GEOMETRY_CHANGED; -#endif -} - -void -HwcHAL::SetCrop(HwcLayer &aLayer, - const hwc_rect_t &aSrcCrop) const -{ - if (GetAPIVersion() >= HwcAPIVersion(1, 3)) { -#if ANDROID_VERSION >= 19 - aLayer.sourceCropf.left = aSrcCrop.left; - aLayer.sourceCropf.top = aSrcCrop.top; - aLayer.sourceCropf.right = aSrcCrop.right; - aLayer.sourceCropf.bottom = aSrcCrop.bottom; -#endif - } else { - aLayer.sourceCrop = aSrcCrop; - } -} - -bool -HwcHAL::EnableVsync(bool aEnable) -{ - // Only support hardware vsync on kitkat, L and up due to inaccurate timings - // with JellyBean. -#if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) - if (!mHwc) { - return false; - } - return !mHwc->eventControl(mHwc, - HWC_DISPLAY_PRIMARY, - HWC_EVENT_VSYNC, - aEnable); -#else - return false; -#endif -} - -bool -HwcHAL::RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) -{ - if (!mHwc || !mHwc->registerProcs) { - printf_stderr("Failed to get hwc\n"); - return false; - } - - // Disable Vsync first, and then register callback functions. - mHwc->eventControl(mHwc, - HWC_DISPLAY_PRIMARY, - HWC_EVENT_VSYNC, - false); - static const hwc_procs_t sHwcJBProcs = {aProcs.invalidate, - aProcs.vsync, - aProcs.hotplug}; - mHwc->registerProcs(mHwc, &sHwcJBProcs); - - // Only support hardware vsync on kitkat, L and up due to inaccurate timings - // with JellyBean. -#if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) - return true; -#else - return false; -#endif -} - -uint32_t -HwcHAL::GetAPIVersion() const -{ - if (!mHwc) { - // default value: HWC_MODULE_API_VERSION_0_1 - return 1; - } - return mHwc->common.version; -} - -// Create HwcHAL -UniquePtr<HwcHALBase> -HwcHALBase::CreateHwcHAL() -{ - return Move(MakeUnique<HwcHAL>()); -} - -} // namespace mozilla diff --git a/widget/gonk/hwchal/HwcHAL.h b/widget/gonk/hwchal/HwcHAL.h deleted file mode 100644 index 05cb6a45f..000000000 --- a/widget/gonk/hwchal/HwcHAL.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcHAL -#define mozilla_HwcHAL - -#include "HwcHALBase.h" - -namespace mozilla { - -class HwcHAL final : public HwcHALBase { -public: - explicit HwcHAL(); - - virtual ~HwcHAL(); - - virtual bool HasHwc() const override { return static_cast<bool>(mHwc); } - - virtual void SetEGLInfo(hwc_display_t aDpy, - hwc_surface_t aSur) override { } - - virtual bool Query(QueryType aType) override; - - virtual int Set(HwcList *aList, - uint32_t aDisp) override; - - virtual int ResetHwc() override; - - virtual int Prepare(HwcList *aList, - uint32_t aDisp, - hwc_rect_t aDispRect, - buffer_handle_t aHandle, - int aFenceFd) override; - - virtual bool SupportTransparency() const override; - - virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const override; - - virtual void SetCrop(HwcLayer &aLayer, - const hwc_rect_t &aSrcCrop) const override; - - virtual bool EnableVsync(bool aEnable) override; - - virtual bool RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) override; - -private: - uint32_t GetAPIVersion() const; - -private: - HwcDevice *mHwc = nullptr; -}; - -} // namespace mozilla - -#endif // mozilla_HwcHAL diff --git a/widget/gonk/hwchal/HwcHALBase.h b/widget/gonk/hwchal/HwcHALBase.h deleted file mode 100644 index 0ef00a325..000000000 --- a/widget/gonk/hwchal/HwcHALBase.h +++ /dev/null @@ -1,134 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcHALBase -#define mozilla_HwcHALBase - -#include "mozilla/UniquePtr.h" -#include "nsRect.h" - -#include <hardware/hwcomposer.h> - -#ifndef HWC_BLIT -#if ANDROID_VERSION >= 21 -#define HWC_BLIT 0xFF -#elif ANDROID_VERSION >= 17 -#define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1) -#else -// ICS didn't support this. However, we define this -// for passing compilation -#define HWC_BLIT 0xFF -#endif // #if ANDROID_VERSION -#endif // #ifndef HWC_BLIT - -namespace mozilla { - -#if ANDROID_VERSION >= 17 -using HwcDevice = hwc_composer_device_1_t; -using HwcList = hwc_display_contents_1_t; -using HwcLayer = hwc_layer_1_t; -#else -using HwcDevice = hwc_composer_device_t; -using HwcList = hwc_layer_list_t; -using HwcLayer = hwc_layer_t; -#endif - -// HwcHAL definition for HwcEvent callback types -// Note: hwc_procs is different between ICS and later, -// and the signature of invalidate is also different. -// Use this wrap struct to hide the detail. BTW, -// we don't have to register callback functions on ICS, so -// there is no callbacks for ICS in HwcHALProcs. -typedef struct HwcHALProcs { - void (*invalidate)(const struct hwc_procs* procs); - void (*vsync)(const struct hwc_procs* procs, int disp, int64_t timestamp); - void (*hotplug)(const struct hwc_procs* procs, int disp, int connected); -} HwcHALProcs_t; - -// HwcHAL class -// This class handle all the HAL related work -// The purpose of HwcHAL is to make HwcComposer2D simpler. -class HwcHALBase { - -public: - // Query Types. We can add more types easily in the future - enum class QueryType { - COLOR_FILL = 0x8, - RB_SWAP = 0x40 - }; - -public: - explicit HwcHALBase() = default; - - virtual ~HwcHALBase() {} - - // Create HwcHAL module, Only HwcComposer2D calls this. - // If other modules want to use HwcHAL, please use APIs in - // HwcComposer2D - static UniquePtr<HwcHALBase> CreateHwcHAL(); - - // Check if mHwc exists - virtual bool HasHwc() const = 0; - - // Set EGL info (only ICS need this info) - virtual void SetEGLInfo(hwc_display_t aEGLDisplay, - hwc_surface_t aEGLSurface) = 0; - - // HwcDevice query properties - virtual bool Query(QueryType aType) = 0; - - // HwcDevice set - virtual int Set(HwcList *aList, - uint32_t aDisp) = 0; - - // Reset HwcDevice - virtual int ResetHwc() = 0; - - // HwcDevice prepare - virtual int Prepare(HwcList *aList, - uint32_t aDisp, - hwc_rect_t aDispRect, - buffer_handle_t aHandle, - int aFenceFd) = 0; - - // Check transparency support - virtual bool SupportTransparency() const = 0; - - // Get a geometry change flag - virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const = 0; - - // Set crop help - virtual void SetCrop(HwcLayer &aLayer, - const hwc_rect_t &aSrcCrop) const = 0; - - // Enable HW Vsync - virtual bool EnableVsync(bool aEnable) = 0; - - // Register HW event callback functions - virtual bool RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) = 0; - -protected: - constexpr static uint32_t HwcAPIVersion(uint32_t aMaj, uint32_t aMin) { - // HARDWARE_MAKE_API_VERSION_2, from Android hardware.h - return (((aMaj & 0xff) << 24) | ((aMin & 0xff) << 16) | (1 & 0xffff)); - } -}; - -} // namespace mozilla - -#endif // mozilla_HwcHALBase diff --git a/widget/gonk/libdisplay/BootAnimation.cpp b/widget/gonk/libdisplay/BootAnimation.cpp deleted file mode 100644 index c275179fc..000000000 --- a/widget/gonk/libdisplay/BootAnimation.cpp +++ /dev/null @@ -1,726 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include <algorithm> -#include <endian.h> -#include <fcntl.h> -#include <pthread.h> -#include <string> -#include <sys/mman.h> -#include <sys/stat.h> -#include <vector> -#include "mozilla/FileUtils.h" -#include "png.h" - -#include "android/log.h" -#include "GonkDisplay.h" -#include "hardware/gralloc.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args) - -using namespace mozilla; -using namespace std; - -static pthread_t sAnimationThread; -static bool sRunAnimation; - -/* See http://www.pkware.com/documents/casestudies/APPNOTE.TXT */ -struct local_file_header { - uint32_t signature; - uint16_t min_version; - uint16_t general_flag; - uint16_t compression; - uint16_t lastmod_time; - uint16_t lastmod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_size; - uint16_t extra_field_size; - char data[0]; - - uint32_t GetDataSize() const - { - return letoh32(uncompressed_size); - } - - uint32_t GetSize() const - { - /* XXX account for data descriptor */ - return sizeof(local_file_header) + letoh16(filename_size) + - letoh16(extra_field_size) + GetDataSize(); - } - - const char * GetData() const - { - return data + letoh16(filename_size) + letoh16(extra_field_size); - } -} __attribute__((__packed__)); - -struct data_descriptor { - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; -} __attribute__((__packed__)); - -struct cdir_entry { - uint32_t signature; - uint16_t creator_version; - uint16_t min_version; - uint16_t general_flag; - uint16_t compression; - uint16_t lastmod_time; - uint16_t lastmod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_size; - uint16_t extra_field_size; - uint16_t file_comment_size; - uint16_t disk_num; - uint16_t internal_attr; - uint32_t external_attr; - uint32_t offset; - char data[0]; - - uint32_t GetDataSize() const - { - return letoh32(compressed_size); - } - - uint32_t GetSize() const - { - return sizeof(cdir_entry) + letoh16(filename_size) + - letoh16(extra_field_size) + letoh16(file_comment_size); - } - - bool Valid() const - { - return signature == htole32(0x02014b50); - } -} __attribute__((__packed__)); - -struct cdir_end { - uint32_t signature; - uint16_t disk_num; - uint16_t cdir_disk; - uint16_t disk_entries; - uint16_t cdir_entries; - uint32_t cdir_size; - uint32_t cdir_offset; - uint16_t comment_size; - char comment[0]; - - bool Valid() const - { - return signature == htole32(0x06054b50); - } -} __attribute__((__packed__)); - -/* We don't have access to libjar and the zip reader in android - * doesn't quite fit what we want to do. */ -class ZipReader { - const char *mBuf; - const cdir_end *mEnd; - const char *mCdir_limit; - uint32_t mBuflen; - -public: - ZipReader() : mBuf(nullptr) {} - ~ZipReader() { - if (mBuf) - munmap((void *)mBuf, mBuflen); - } - - bool OpenArchive(const char *path) - { - int fd; - do { - fd = open(path, O_RDONLY); - } while (fd == -1 && errno == EINTR); - if (fd == -1) - return false; - - struct stat sb; - if (fstat(fd, &sb) == -1 || sb.st_size < sizeof(cdir_end)) { - close(fd); - return false; - } - - mBuflen = sb.st_size; - mBuf = (char *)mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); - close(fd); - - if (!mBuf) { - return false; - } - - madvise(mBuf, sb.st_size, MADV_SEQUENTIAL); - - mEnd = (cdir_end *)(mBuf + mBuflen - sizeof(cdir_end)); - while (!mEnd->Valid() && - (char *)mEnd > mBuf) { - mEnd = (cdir_end *)((char *)mEnd - 1); - } - - mCdir_limit = mBuf + letoh32(mEnd->cdir_offset) + letoh32(mEnd->cdir_size); - - if (!mEnd->Valid() || mCdir_limit > (char *)mEnd) { - munmap((void *)mBuf, mBuflen); - mBuf = nullptr; - return false; - } - - return true; - } - - /* Pass null to get the first cdir entry */ - const cdir_entry * GetNextEntry(const cdir_entry *prev) - { - const cdir_entry *entry; - if (prev) - entry = (cdir_entry *)((char *)prev + prev->GetSize()); - else - entry = (cdir_entry *)(mBuf + letoh32(mEnd->cdir_offset)); - - if (((char *)entry + entry->GetSize()) > mCdir_limit || - !entry->Valid()) - return nullptr; - return entry; - } - - string GetEntryName(const cdir_entry *entry) - { - uint16_t len = letoh16(entry->filename_size); - - string name; - name.append(entry->data, len); - return name; - } - - const local_file_header * GetLocalEntry(const cdir_entry *entry) - { - const local_file_header * data = - (local_file_header *)(mBuf + letoh32(entry->offset)); - if (((char *)data + data->GetSize()) > (char *)mEnd) - return nullptr; - return data; - } -}; - -struct AnimationFrame { - char path[256]; - png_color_16 bgcolor; - char *buf; - const local_file_header *file; - uint32_t width; - uint32_t height; - uint16_t bytepp; - bool has_bgcolor; - - AnimationFrame() : buf(nullptr) {} - AnimationFrame(const AnimationFrame &frame) : buf(nullptr) { - strncpy(path, frame.path, sizeof(path)); - file = frame.file; - } - ~AnimationFrame() - { - if (buf) - free(buf); - } - - bool operator<(const AnimationFrame &other) const - { - return strcmp(path, other.path) < 0; - } - - void ReadPngFrame(int outputFormat); -}; - -struct AnimationPart { - int32_t count; - int32_t pause; - // If you alter the size of the path, change ReadFromString() as well. - char path[256]; - vector<AnimationFrame> frames; - - bool - ReadFromString(const char* aLine) - { - MOZ_ASSERT(aLine); - // this 255 value must be in sync with AnimationPart::path. - return sscanf(aLine, "p %d %d %255s", &count, &pause, path) == 3; - } -}; - -struct RawReadState { - const char *start; - uint32_t offset; - uint32_t length; -}; - -static void -RawReader(png_structp png_ptr, png_bytep data, png_size_t length) -{ - RawReadState *state = (RawReadState *)png_get_io_ptr(png_ptr); - if (length > (state->length - state->offset)) - png_error(png_ptr, "PNG read overrun"); - - memcpy(data, state->start + state->offset, length); - state->offset += length; -} - -static void -TransformTo565(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - uint16_t *outbuf = (uint16_t *)data; - uint8_t *inbuf = (uint8_t *)data; - for (uint32_t i = 0; i < row_info->rowbytes; i += 3) { - *outbuf++ = ((inbuf[i] & 0xF8) << 8) | - ((inbuf[i + 1] & 0xFC) << 3) | - ((inbuf[i + 2] ) >> 3); - } -} - -static uint16_t -GetFormatBPP(int aFormat) -{ - uint16_t bpp = 0; - - switch (aFormat) { - case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - bpp = 4; - break; - case HAL_PIXEL_FORMAT_RGB_888: - bpp = 3; - break; - default: - LOGW("Unknown pixel format %d. Assuming RGB 565.", aFormat); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGB_565: - bpp = 2; - break; - } - - return bpp; -} - -void -AnimationFrame::ReadPngFrame(int outputFormat) -{ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - static const png_byte unused_chunks[] = - { 99, 72, 82, 77, '\0', /* cHRM */ - 104, 73, 83, 84, '\0', /* hIST */ - 105, 67, 67, 80, '\0', /* iCCP */ - 105, 84, 88, 116, '\0', /* iTXt */ - 111, 70, 70, 115, '\0', /* oFFs */ - 112, 67, 65, 76, '\0', /* pCAL */ - 115, 67, 65, 76, '\0', /* sCAL */ - 112, 72, 89, 115, '\0', /* pHYs */ - 115, 66, 73, 84, '\0', /* sBIT */ - 115, 80, 76, 84, '\0', /* sPLT */ - 116, 69, 88, 116, '\0', /* tEXt */ - 116, 73, 77, 69, '\0', /* tIME */ - 122, 84, 88, 116, '\0'}; /* zTXt */ - static const png_byte tRNS_chunk[] = - {116, 82, 78, 83, '\0'}; /* tRNS */ -#endif - - png_structp pngread = png_create_read_struct(PNG_LIBPNG_VER_STRING, - nullptr, nullptr, nullptr); - - if (!pngread) - return; - - png_infop pnginfo = png_create_info_struct(pngread); - - if (!pnginfo) { - png_destroy_read_struct(&pngread, &pnginfo, nullptr); - return; - } - - if (setjmp(png_jmpbuf(pngread))) { - // libpng reported an error and longjumped here. Clean up and return. - png_destroy_read_struct(&pngread, &pnginfo, nullptr); - return; - } - - RawReadState state; - state.start = file->GetData(); - state.length = file->GetDataSize(); - state.offset = 0; - - png_set_read_fn(pngread, &state, RawReader); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - /* Ignore unused chunks */ - png_set_keep_unknown_chunks(pngread, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - - /* Ignore the tRNS chunk if we only want opaque output */ - if (outputFormat == HAL_PIXEL_FORMAT_RGB_888 || - outputFormat == HAL_PIXEL_FORMAT_RGB_565) { - png_set_keep_unknown_chunks(pngread, 1, tRNS_chunk, 1); - } -#endif - - png_read_info(pngread, pnginfo); - - png_color_16p colorp; - has_bgcolor = (PNG_INFO_bKGD == png_get_bKGD(pngread, pnginfo, &colorp)); - bgcolor = has_bgcolor ? *colorp : png_color_16(); - width = png_get_image_width(pngread, pnginfo); - height = png_get_image_height(pngread, pnginfo); - - LOG("Decoded %s: %d x %d frame with bgcolor? %s (%#x, %#x, %#x; gray:%#x)", - path, width, height, has_bgcolor ? "yes" : "no", - bgcolor.red, bgcolor.green, bgcolor.blue, bgcolor.gray); - - bytepp = GetFormatBPP(outputFormat); - - switch (outputFormat) { - case HAL_PIXEL_FORMAT_BGRA_8888: - png_set_bgr(pngread); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - png_set_filler(pngread, 0xFF, PNG_FILLER_AFTER); - break; - case HAL_PIXEL_FORMAT_RGB_888: - png_set_strip_alpha(pngread); - break; - default: - LOGW("Unknown pixel format %d. Assuming RGB 565.", outputFormat); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGB_565: - png_set_strip_alpha(pngread); - png_set_read_user_transform_fn(pngread, TransformTo565); - break; - } - - // An extra row is added to give libpng enough space when - // decoding 3/4 bytepp inputs for 2 bytepp output surfaces - buf = (char *)malloc(width * (height + 1) * bytepp); - - vector<char *> rows(height + 1); - uint32_t stride = width * bytepp; - for (uint32_t i = 0; i < height; i++) { - rows[i] = buf + (stride * i); - } - rows[height] = nullptr; - png_set_strip_16(pngread); - png_set_palette_to_rgb(pngread); - png_set_gray_to_rgb(pngread); - png_read_image(pngread, (png_bytepp)&rows.front()); - png_destroy_read_struct(&pngread, &pnginfo, nullptr); -} - -/** - * Return a wchar_t that when used to |wmemset()| an image buffer will - * fill it with the color defined by |color16|. The packed wchar_t - * may comprise one or two pixels depending on |outputFormat|. - */ -static wchar_t -AsBackgroundFill(const png_color_16& color16, int outputFormat) -{ - static_assert(sizeof(wchar_t) == sizeof(uint32_t), - "TODO: support 2-byte wchar_t"); - union { - uint32_t r8g8b8; - struct { - uint8_t b8; - uint8_t g8; - uint8_t r8; - uint8_t x8; - }; - } color; - color.b8 = color16.blue; - color.g8 = color16.green; - color.r8 = color16.red; - color.x8 = 0xFF; - - switch (outputFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - return color.r8g8b8; - - case HAL_PIXEL_FORMAT_BGRA_8888: - swap(color.r8, color.b8); - return color.r8g8b8; - - case HAL_PIXEL_FORMAT_RGB_565: { - // NB: we could do a higher-quality downsample here, but we - // want the results to be a pixel-perfect match with the fast - // downsample in TransformTo565(). - uint16_t color565 = ((color.r8 & 0xF8) << 8) | - ((color.g8 & 0xFC) << 3) | - ((color.b8 ) >> 3); - return (color565 << 16) | color565; - } - default: - LOGW("Unhandled pixel format %d; falling back on black", outputFormat); - return 0; - } -} - -void -ShowSolidColorFrame(GonkDisplay *aDisplay, - const gralloc_module_t *grallocModule, - int32_t aFormat) -{ - LOGW("Show solid color frame for bootAnim"); - - ANativeWindowBuffer *buffer = aDisplay->DequeueBuffer(); - void *mappedAddress = nullptr; - - if (!buffer) { - LOGW("Failed to get an ANativeWindowBuffer"); - return; - } - - if (!grallocModule->lock(grallocModule, buffer->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, buffer->width, buffer->height, &mappedAddress)) { - // Just show a black solid color frame. - memset(mappedAddress, 0, buffer->height * buffer->stride * GetFormatBPP(aFormat)); - grallocModule->unlock(grallocModule, buffer->handle); - } - - aDisplay->QueueBuffer(buffer); -} - -static void * -AnimationThread(void *) -{ - GonkDisplay *display = GetGonkDisplay(); - int32_t format = display->surfaceformat; - - const hw_module_t *module = nullptr; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) { - LOGW("Could not get gralloc module"); - return nullptr; - } - const gralloc_module_t *grmodule = - reinterpret_cast<gralloc_module_t const*>(module); - - ZipReader reader; - if (!reader.OpenArchive("/system/media/bootanimation.zip")) { - LOGW("Could not open boot animation"); - ShowSolidColorFrame(display, grmodule, format); - return nullptr; - } - - const cdir_entry *entry = nullptr; - const local_file_header *file = nullptr; - while ((entry = reader.GetNextEntry(entry))) { - string name = reader.GetEntryName(entry); - if (!name.compare("desc.txt")) { - file = reader.GetLocalEntry(entry); - break; - } - } - - if (!file) { - LOGW("Could not find desc.txt in boot animation"); - ShowSolidColorFrame(display, grmodule, format); - return nullptr; - } - - string descCopy; - descCopy.append(file->GetData(), entry->GetDataSize()); - int32_t width, height, fps; - const char *line = descCopy.c_str(); - const char *end; - bool headerRead = true; - vector<AnimationPart> parts; - bool animPlayed = false; - - /* - * bootanimation.zip - * - * This is the boot animation file format that Android uses. - * It's a zip file with a directories containing png frames - * and a desc.txt that describes how they should be played. - * - * desc.txt contains two types of lines - * 1. [width] [height] [fps] - * There is one of these lines per bootanimation. - * If the width and height are smaller than the screen, - * the frames are centered on a black background. - * XXX: Currently we stretch instead of centering the frame. - * 2. p [count] [pause] [path] - * This describes one animation part. - * Each animation part is played in sequence. - * An animation part contains all the files/frames in the - * directory specified in [path] - * [count] indicates the number of times this part repeats. - * [pause] indicates the number of frames that this part - * should pause for after playing the full sequence but - * before repeating. - */ - - do { - end = strstr(line, "\n"); - - AnimationPart part; - if (headerRead && - sscanf(line, "%d %d %d", &width, &height, &fps) == 3) { - headerRead = false; - } else if (part.ReadFromString(line)) { - parts.push_back(part); - } - } while (end && *(line = end + 1)); - - for (uint32_t i = 0; i < parts.size(); i++) { - AnimationPart &part = parts[i]; - entry = nullptr; - char search[256]; - snprintf(search, sizeof(search), "%s/", part.path); - while ((entry = reader.GetNextEntry(entry))) { - string name = reader.GetEntryName(entry); - if (name.find(search) || - !entry->GetDataSize() || - name.length() >= 256) - continue; - - part.frames.resize(part.frames.size() + 1); - AnimationFrame &frame = part.frames.back(); - strcpy(frame.path, name.c_str()); - frame.file = reader.GetLocalEntry(entry); - } - - sort(part.frames.begin(), part.frames.end()); - } - - long int frameDelayUs = 1000000 / fps; - - for (uint32_t i = 0; i < parts.size(); i++) { - AnimationPart &part = parts[i]; - - int32_t j = 0; - while (sRunAnimation && (!part.count || j++ < part.count)) { - for (uint32_t k = 0; k < part.frames.size(); k++) { - struct timeval tv1, tv2; - gettimeofday(&tv1, nullptr); - AnimationFrame &frame = part.frames[k]; - if (!frame.buf) { - frame.ReadPngFrame(format); - } - - ANativeWindowBuffer *buf = display->DequeueBuffer(); - if (!buf) { - LOGW("Failed to get an ANativeWindowBuffer"); - break; - } - - void *vaddr; - if (grmodule->lock(grmodule, buf->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, width, height, &vaddr)) { - LOGW("Failed to lock buffer_handle_t"); - display->QueueBuffer(buf); - break; - } - - if (frame.has_bgcolor) { - wchar_t bgfill = AsBackgroundFill(frame.bgcolor, format); - wmemset((wchar_t*)vaddr, bgfill, - (buf->height * buf->stride * frame.bytepp) / sizeof(wchar_t)); - } - - if ((uint32_t)buf->height == frame.height && (uint32_t)buf->stride == frame.width) { - memcpy(vaddr, frame.buf, - frame.width * frame.height * frame.bytepp); - } else if ((uint32_t)buf->height >= frame.height && - (uint32_t)buf->width >= frame.width) { - int startx = (buf->width - frame.width) / 2; - int starty = (buf->height - frame.height) / 2; - - int src_stride = frame.width * frame.bytepp; - int dst_stride = buf->stride * frame.bytepp; - - char *src = frame.buf; - char *dst = (char *) vaddr + starty * dst_stride + startx * frame.bytepp; - - for (uint32_t i = 0; i < frame.height; i++) { - memcpy(dst, src, src_stride); - src += src_stride; - dst += dst_stride; - } - } - grmodule->unlock(grmodule, buf->handle); - - gettimeofday(&tv2, nullptr); - - timersub(&tv2, &tv1, &tv2); - - if (tv2.tv_usec < frameDelayUs) { - usleep(frameDelayUs - tv2.tv_usec); - } else { - LOGW("Frame delay is %ld us but decoding took %ld us", - frameDelayUs, tv2.tv_usec); - } - - animPlayed = true; - display->QueueBuffer(buf); - - if (part.count && j >= part.count) { - free(frame.buf); - frame.buf = nullptr; - } - } - usleep(frameDelayUs * part.pause); - } - } - - if (!animPlayed) { - ShowSolidColorFrame(display, grmodule, format); - } - - return nullptr; -} - -namespace mozilla { - -__attribute__ ((visibility ("default"))) -void -StartBootAnimation() -{ - GetGonkDisplay(); // Ensure GonkDisplay exist - sRunAnimation = true; - pthread_create(&sAnimationThread, nullptr, AnimationThread, nullptr); -} - -__attribute__ ((visibility ("default"))) -void -StopBootAnimation() -{ - if (sRunAnimation) { - sRunAnimation = false; - pthread_join(sAnimationThread, nullptr); - GetGonkDisplay()->NotifyBootAnimationStopped(); - } -} - -} // namespace mozilla diff --git a/widget/gonk/libdisplay/BootAnimation.h b/widget/gonk/libdisplay/BootAnimation.h deleted file mode 100644 index 9fdc20eca..000000000 --- a/widget/gonk/libdisplay/BootAnimation.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef BOOTANIMATION_H -#define BOOTANIMATION_H - -namespace mozilla { - -MOZ_EXPORT __attribute__ ((weak)) -void StartBootAnimation(); - -/* Stop the boot animation if it's still running. */ -MOZ_EXPORT __attribute__ ((weak)) -void StopBootAnimation(); - -} // namespace mozilla - -#endif /* BOOTANIMATION_H */ diff --git a/widget/gonk/libdisplay/DisplaySurface.h b/widget/gonk/libdisplay/DisplaySurface.h deleted file mode 100644 index 398541c49..000000000 --- a/widget/gonk/libdisplay/DisplaySurface.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_SF_DISPLAY_SURFACE_H -#define ANDROID_SF_DISPLAY_SURFACE_H - -#include <gui/ConsumerBase.h> -#include <system/window.h> -#include <utils/Errors.h> -#include <utils/RefBase.h> -#include <utils/StrongPointer.h> - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -class IGraphicBufferProducer; -class String8; - -#if ANDROID_VERSION >= 21 -typedef IGraphicBufferConsumer StreamConsumer; -#else -typedef BufferQueue StreamConsumer; -#endif - -class DisplaySurface : public ConsumerBase { -public: - // beginFrame is called at the beginning of the composition loop, before - // the configuration is known. The DisplaySurface should do anything it - // needs to do to enable HWComposer to decide how to compose the frame. - // We pass in mustRecompose so we can keep VirtualDisplaySurface's state - // machine happy without actually queueing a buffer if nothing has changed. - virtual status_t beginFrame(bool mustRecompose) = 0; - - // prepareFrame is called after the composition configuration is known but - // before composition takes place. The DisplaySurface can use the - // composition type to decide how to manage the flow of buffers between - // GLES and HWC for this frame. - enum CompositionType { - COMPOSITION_UNKNOWN = 0, - COMPOSITION_GLES = 1, - COMPOSITION_HWC = 2, - COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC - }; - virtual status_t prepareFrame(CompositionType compositionType) = 0; - - // Should be called when composition rendering is complete for a frame (but - // eglSwapBuffers hasn't necessarily been called). Required by certain - // older drivers for synchronization. - // TODO: Remove this when we drop support for HWC 1.0. - virtual status_t compositionComplete() = 0; - - // Inform the surface that GLES composition is complete for this frame, and - // the surface should make sure that HWComposer has the correct buffer for - // this frame. Some implementations may only push a new buffer to - // HWComposer if GLES composition took place, others need to push a new - // buffer on every frame. - // - // advanceFrame must be followed by a call to onFrameCommitted before - // advanceFrame may be called again. - virtual status_t advanceFrame() = 0; - - // onFrameCommitted is called after the frame has been committed to the - // hardware composer. The surface collects the release fence for this - // frame's buffer. - virtual void onFrameCommitted() = 0; - - virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0; - - // setReleaseFenceFd stores a fence file descriptor that will signal when the - // current buffer is no longer being read. This fence will be returned to - // the producer when the current buffer is released by updateTexImage(). - // Multiple fences can be set for a given buffer; they will be merged into - // a single union fence. The SurfaceTexture will close the file descriptor - // when finished with it. - virtual status_t setReleaseFenceFd(int fenceFd) = 0; - - virtual int GetPrevDispAcquireFd() = 0; - - buffer_handle_t lastHandle; - -protected: - DisplaySurface(const sp<StreamConsumer>& sc) -#if ANDROID_VERSION >= 19 - : ConsumerBase(sc, true) -#else - : ConsumerBase(sc) -#endif - , lastHandle(0) - { } - virtual ~DisplaySurface() {} -}; - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_DISPLAY_SURFACE_H - diff --git a/widget/gonk/libdisplay/FramebufferSurface.cpp b/widget/gonk/libdisplay/FramebufferSurface.cpp deleted file mode 100644 index a289acbb8..000000000 --- a/widget/gonk/libdisplay/FramebufferSurface.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - ** - ** Copyright 2012 The Android Open Source Project - ** - ** 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. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <errno.h> - -#include <cutils/log.h> - -#include <utils/String8.h> - -#include <ui/Rect.h> - -#include <EGL/egl.h> - -#include <hardware/hardware.h> -#if ANDROID_VERSION == 17 -#include <gui/SurfaceTextureClient.h> -#endif -#include <ui/GraphicBuffer.h> - -#include "FramebufferSurface.h" -#include "GraphicBufferAlloc.h" - -#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS -#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2) -#endif - -// ---------------------------------------------------------------------------- -namespace android { -// ---------------------------------------------------------------------------- - -/* - * This implements the (main) framebuffer management. This class - * was adapted from the version in SurfaceFlinger - */ -FramebufferSurface::FramebufferSurface(int disp, - uint32_t width, - uint32_t height, - uint32_t format, - const sp<StreamConsumer>& sc) - : DisplaySurface(sc) - , mDisplayType(disp) - , mCurrentBufferSlot(-1) - , mCurrentBuffer(0) -{ - mName = "FramebufferSurface"; - -#if ANDROID_VERSION >= 19 - sp<IGraphicBufferConsumer> consumer = mConsumer; -#else - sp<BufferQueue> consumer = mBufferQueue; - consumer->setSynchronousMode(true); -#endif - consumer->setConsumerName(mName); - consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_COMPOSER); - consumer->setDefaultBufferFormat(format); - consumer->setDefaultBufferSize(width, height); - consumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); -} - -status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { - return NO_ERROR; -} - -status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) { - return NO_ERROR; -} - -status_t FramebufferSurface::advanceFrame() { - // Once we remove FB HAL support, we can call nextBuffer() from here - // instead of using onFrameAvailable(). No real benefit, except it'll be - // more like VirtualDisplaySurface. - return NO_ERROR; -} - -status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) { - Mutex::Autolock lock(mMutex); - - BufferQueue::BufferItem item; -#if ANDROID_VERSION >= 19 - status_t err = acquireBufferLocked(&item, 0); -#else - status_t err = acquireBufferLocked(&item); -#endif - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - outBuffer = mCurrentBuffer; - return NO_ERROR; - } else if (err != NO_ERROR) { - ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); - return err; - } - - // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot - // then we may have acquired the slot we already own. If we had released - // our current buffer before we call acquireBuffer then that release call - // would have returned STALE_BUFFER_SLOT, and we would have called - // freeBufferLocked on that slot. Because the buffer slot has already - // been overwritten with the new buffer all we have to do is skip the - // releaseBuffer call and we should be in the same state we'd be in if we - // had released the old buffer first. - if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && - item.mBuf != mCurrentBufferSlot) { - // Release the previous buffer. -#if ANDROID_VERSION >= 19 - err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); -#else - err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); -#endif - if (err != NO_ERROR && err != StreamConsumer::STALE_BUFFER_SLOT) { - ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); - return err; - } - } - mCurrentBufferSlot = item.mBuf; - mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; - outFence = item.mFence; - outBuffer = mCurrentBuffer; - return NO_ERROR; -} - -// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. -#if ANDROID_VERSION >= 22 -void FramebufferSurface::onFrameAvailable(const ::android::BufferItem &item) { -#else -void FramebufferSurface::onFrameAvailable() { -#endif - sp<GraphicBuffer> buf; - sp<Fence> acquireFence; - status_t err = nextBuffer(buf, acquireFence); - if (err != NO_ERROR) { - ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", - strerror(-err), err); - return; - } - if (acquireFence.get() && acquireFence->isValid()) - mPrevFBAcquireFence = new Fence(acquireFence->dup()); - else - mPrevFBAcquireFence = Fence::NO_FENCE; - - lastHandle = buf->handle; -} - -void FramebufferSurface::freeBufferLocked(int slotIndex) { - ConsumerBase::freeBufferLocked(slotIndex); - if (slotIndex == mCurrentBufferSlot) { - mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; - } -} - -status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) { - status_t err = NO_ERROR; - if (fenceFd >= 0) { - sp<Fence> fence(new Fence(fenceFd)); - if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { -#if ANDROID_VERSION >= 19 - status_t err = addReleaseFence(mCurrentBufferSlot, mCurrentBuffer, fence); -#else - status_t err = addReleaseFence(mCurrentBufferSlot, fence); -#endif - ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", - strerror(-err), err); - } - } - return err; -} - -int FramebufferSurface::GetPrevDispAcquireFd() { - if (mPrevFBAcquireFence.get() && mPrevFBAcquireFence->isValid()) { - return mPrevFBAcquireFence->dup(); - } - return -1; -} - -void FramebufferSurface::onFrameCommitted() { - // XXX This role is almost same to setReleaseFenceFd(). -} - -status_t FramebufferSurface::compositionComplete() -{ - // Actual implementaiton is in GonkDisplay::SwapBuffers() - // XXX need to move that to here. - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- diff --git a/widget/gonk/libdisplay/FramebufferSurface.h b/widget/gonk/libdisplay/FramebufferSurface.h deleted file mode 100644 index c1cc84272..000000000 --- a/widget/gonk/libdisplay/FramebufferSurface.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H -#define ANDROID_SF_FRAMEBUFFER_SURFACE_H - -#include <stdint.h> -#include <sys/types.h> - -#include "DisplaySurface.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -class Rect; -class String8; - -// --------------------------------------------------------------------------- - -class FramebufferSurface : public DisplaySurface { -public: - FramebufferSurface(int disp, uint32_t width, uint32_t height, uint32_t format, const sp<StreamConsumer>& sc); - - // From DisplaySurface - virtual status_t beginFrame(bool mustRecompose); - virtual status_t prepareFrame(CompositionType compositionType); - virtual status_t compositionComplete(); - virtual status_t advanceFrame(); - virtual void onFrameCommitted(); - // Cannot resize a buffers in a FramebufferSurface. Only works with virtual - // displays. - virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { }; - - // setReleaseFenceFd stores a fence file descriptor that will signal when the - // current buffer is no longer being read. This fence will be returned to - // the producer when the current buffer is released by updateTexImage(). - // Multiple fences can be set for a given buffer; they will be merged into - // a single union fence. The SurfaceTexture will close the file descriptor - // when finished with it. - status_t setReleaseFenceFd(int fenceFd); - - virtual int GetPrevDispAcquireFd(); - -private: - virtual ~FramebufferSurface() { }; // this class cannot be overloaded - -#if ANDROID_VERSION >= 22 - virtual void onFrameAvailable(const ::android::BufferItem &item); -#else - virtual void onFrameAvailable(); -#endif - virtual void freeBufferLocked(int slotIndex); - - // nextBuffer waits for and then latches the next buffer from the - // BufferQueue and releases the previously latched buffer to the - // BufferQueue. The new buffer is returned in the 'buffer' argument. - status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence); - - // mDisplayType must match one of the HWC display types - int mDisplayType; - - // mCurrentBufferIndex is the slot index of the current buffer or - // INVALID_BUFFER_SLOT to indicate that either there is no current buffer - // or the buffer is not associated with a slot. - int mCurrentBufferSlot; - - // mCurrentBuffer is the current buffer or NULL to indicate that there is - // no current buffer. - sp<GraphicBuffer> mCurrentBuffer; - - android::sp<android::Fence> mPrevFBAcquireFence; -}; - -// --------------------------------------------------------------------------- -}; // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H - diff --git a/widget/gonk/libdisplay/GonkDisplay.h b/widget/gonk/libdisplay/GonkDisplay.h deleted file mode 100644 index 96978a6e9..000000000 --- a/widget/gonk/libdisplay/GonkDisplay.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GONKDISPLAY_H -#define GONKDISPLAY_H - -#include <system/window.h> -#include <utils/StrongPointer.h> -#include "mozilla/Types.h" - -namespace android { -class DisplaySurface; -class IGraphicBufferProducer; -} - -namespace mozilla { - -typedef void * EGLDisplay; -typedef void * EGLSurface; - -class MOZ_EXPORT GonkDisplay { -public: - /** - * This enum is for types of display. DISPLAY_PRIMARY refers to the default - * built-in display, DISPLAY_EXTERNAL refers to displays connected with - * HDMI, and DISPLAY_VIRTUAL are displays which makes composited output - * available within the system. Currently, displays of external are detected - * via the hotplug detection in HWC, and displays of virtual are connected - * via Wifi Display. - */ - enum DisplayType { - DISPLAY_PRIMARY, - DISPLAY_EXTERNAL, - DISPLAY_VIRTUAL, - NUM_DISPLAY_TYPES - }; - - struct NativeData { - android::sp<ANativeWindow> mNativeWindow; -#if ANDROID_VERSION >= 17 - android::sp<android::DisplaySurface> mDisplaySurface; -#endif - float mXdpi; - }; - - virtual void SetEnabled(bool enabled) = 0; - - typedef void (*OnEnabledCallbackType)(bool enabled); - - virtual void OnEnabled(OnEnabledCallbackType callback) = 0; - - virtual void* GetHWCDevice() = 0; - - /** - * Only GonkDisplayICS uses arguments. - */ - virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur) = 0; - - virtual ANativeWindowBuffer* DequeueBuffer() = 0; - - virtual bool QueueBuffer(ANativeWindowBuffer* buf) = 0; - - virtual void UpdateDispSurface(EGLDisplay dpy, EGLSurface sur) = 0; - - virtual NativeData GetNativeData( - GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink = nullptr) = 0; - - virtual void NotifyBootAnimationStopped() = 0; - - float xdpi; - int32_t surfaceformat; -}; - -MOZ_EXPORT __attribute__ ((weak)) -GonkDisplay* GetGonkDisplay(); - -} -#endif /* GONKDISPLAY_H */ diff --git a/widget/gonk/libdisplay/GonkDisplayJB.cpp b/widget/gonk/libdisplay/GonkDisplayJB.cpp deleted file mode 100644 index 197b85a47..000000000 --- a/widget/gonk/libdisplay/GonkDisplayJB.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "GonkDisplayJB.h" -#if ANDROID_VERSION == 17 -#include <gui/SurfaceTextureClient.h> -#else -#include <gui/Surface.h> -#include <gui/GraphicBufferAlloc.h> -#endif - -#include <hardware/hardware.h> -#include <hardware/hwcomposer.h> -#include <hardware/power.h> -#include <suspend/autosuspend.h> - -#if ANDROID_VERSION >= 19 -#include "VirtualDisplaySurface.h" -#endif -#include "FramebufferSurface.h" -#if ANDROID_VERSION == 17 -#include "GraphicBufferAlloc.h" -#endif -#include "mozilla/Assertions.h" - -#define DEFAULT_XDPI 75.0 - -using namespace android; - -namespace mozilla { - -static GonkDisplayJB* sGonkDisplay = nullptr; - -GonkDisplayJB::GonkDisplayJB() - : mModule(nullptr) - , mFBModule(nullptr) - , mHwc(nullptr) - , mFBDevice(nullptr) - , mPowerModule(nullptr) - , mList(nullptr) - , mWidth(0) - , mHeight(0) - , mEnabledCallback(nullptr) -{ - int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mFBModule); - ALOGW_IF(err, "%s module not found", GRALLOC_HARDWARE_MODULE_ID); - if (!err) { - err = framebuffer_open(mFBModule, &mFBDevice); - ALOGW_IF(err, "could not open framebuffer"); - } - - if (!err && mFBDevice) { - mWidth = mFBDevice->width; - mHeight = mFBDevice->height; - xdpi = mFBDevice->xdpi; - /* The emulator actually reports RGBA_8888, but EGL doesn't return - * any matching configuration. We force RGBX here to fix it. */ - surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888; - } - - err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); - ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); - if (!err) { - err = hwc_open_1(mModule, &mHwc); - ALOGE_IF(err, "%s device failed to initialize (%s)", - HWC_HARDWARE_COMPOSER, strerror(-err)); - } - - /* Fallback on the FB rendering path instead of trying to support HWC 1.0 */ - if (!err && mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) { - hwc_close_1(mHwc); - mHwc = nullptr; - } - - if (!err && mHwc) { - if (mFBDevice) { - framebuffer_close(mFBDevice); - mFBDevice = nullptr; - } - - int32_t values[3]; - const uint32_t attrs[] = { - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_NO_ATTRIBUTE - }; - mHwc->getDisplayAttributes(mHwc, 0, 0, attrs, values); - - mWidth = values[0]; - mHeight = values[1]; - xdpi = values[2] / 1000.0f; - surfaceformat = HAL_PIXEL_FORMAT_RGBA_8888; - } - - err = hw_get_module(POWER_HARDWARE_MODULE_ID, - (hw_module_t const**)&mPowerModule); - if (!err) - mPowerModule->init(mPowerModule); - ALOGW_IF(err, "Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err)); - - mAlloc = new GraphicBufferAlloc(); - - CreateFramebufferSurface(mSTClient, mDispSurface, mWidth, mHeight); - - mList = (hwc_display_contents_1_t *)calloc(1, sizeof(*mList) + (sizeof(hwc_layer_1_t)*2)); - - uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; - if (mFBDevice) { - // If device uses fb, they can not use single buffer for boot animation - mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2); - mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE, usage); - } else if (mHwc) { - PowerOnDisplay(HWC_DISPLAY_PRIMARY); - // For devices w/ hwc v1.0 or no hwc, this buffer can not be created, - // only create this buffer for devices w/ hwc version > 1.0. - CreateFramebufferSurface(mBootAnimSTClient, mBootAnimDispSurface, mWidth, mHeight); - } -} - -GonkDisplayJB::~GonkDisplayJB() -{ - if (mHwc) - hwc_close_1(mHwc); - if (mFBDevice) - framebuffer_close(mFBDevice); - free(mList); -} - -void -GonkDisplayJB::CreateFramebufferSurface(android::sp<ANativeWindow>& aNativeWindow, - android::sp<android::DisplaySurface>& aDisplaySurface, - uint32_t aWidth, - uint32_t aHeight) -{ -#if ANDROID_VERSION >= 21 - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer, mAlloc); -#elif ANDROID_VERSION >= 19 - sp<BufferQueue> consumer = new BufferQueue(mAlloc); - sp<IGraphicBufferProducer> producer = consumer; -#elif ANDROID_VERSION >= 18 - sp<BufferQueue> consumer = new BufferQueue(true, mAlloc); - sp<IGraphicBufferProducer> producer = consumer; -#else - sp<BufferQueue> consumer = new BufferQueue(true, mAlloc); -#endif - - aDisplaySurface = new FramebufferSurface(0, aWidth, aHeight, surfaceformat, consumer); - -#if ANDROID_VERSION == 17 - aNativeWindow = new SurfaceTextureClient( - static_cast<sp<ISurfaceTexture>>(aDisplaySurface->getBufferQueue())); -#else - aNativeWindow = new Surface(producer); -#endif -} - -void -GonkDisplayJB::CreateVirtualDisplaySurface(android::IGraphicBufferProducer* aSink, - android::sp<ANativeWindow>& aNativeWindow, - android::sp<android::DisplaySurface>& aDisplaySurface) -{ -#if ANDROID_VERSION >= 21 - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - BufferQueue::createBufferQueue(&producer, &consumer, mAlloc); -#elif ANDROID_VERSION >= 19 - sp<BufferQueue> consumer = new BufferQueue(mAlloc); - sp<IGraphicBufferProducer> producer = consumer; -#endif - -#if ANDROID_VERSION >= 19 - sp<VirtualDisplaySurface> virtualDisplay; - virtualDisplay = new VirtualDisplaySurface(-1, aSink, producer, consumer, String8("VirtualDisplaySurface")); - aDisplaySurface = virtualDisplay; - aNativeWindow = new Surface(virtualDisplay); -#endif -} - -void -GonkDisplayJB::SetEnabled(bool enabled) -{ - if (enabled) { - autosuspend_disable(); - mPowerModule->setInteractive(mPowerModule, true); - } - - if (!enabled && mEnabledCallback) { - mEnabledCallback(enabled); - } - -#if ANDROID_VERSION >= 21 - if (mHwc) { - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) { - mHwc->setPowerMode(mHwc, HWC_DISPLAY_PRIMARY, - (enabled ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF)); - } else { - mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled); - } - } else if (mFBDevice && mFBDevice->enableScreen) { - mFBDevice->enableScreen(mFBDevice, enabled); - } -#else - if (mHwc && mHwc->blank) { - mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled); - } else if (mFBDevice && mFBDevice->enableScreen) { - mFBDevice->enableScreen(mFBDevice, enabled); - } -#endif - - if (enabled && mEnabledCallback) { - mEnabledCallback(enabled); - } - - if (!enabled) { - autosuspend_enable(); - mPowerModule->setInteractive(mPowerModule, false); - } -} - -void -GonkDisplayJB::OnEnabled(OnEnabledCallbackType callback) -{ - mEnabledCallback = callback; -} - -void* -GonkDisplayJB::GetHWCDevice() -{ - return mHwc; -} - -bool -GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur) -{ - // Should be called when composition rendering is complete for a frame. - // Only HWC v1.0 needs this call. - // HWC > v1.0 case, do not call compositionComplete(). - // mFBDevice is present only when HWC is v1.0. - if (mFBDevice && mFBDevice->compositionComplete) { - mFBDevice->compositionComplete(mFBDevice); - } - return Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd()); -} - -bool -GonkDisplayJB::Post(buffer_handle_t buf, int fence) -{ - if (!mHwc) { - if (fence >= 0) - close(fence); - return !mFBDevice->post(mFBDevice, buf); - } - - hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = {NULL}; - const hwc_rect_t r = { 0, 0, static_cast<int>(mWidth), static_cast<int>(mHeight) }; - displays[HWC_DISPLAY_PRIMARY] = mList; - mList->retireFenceFd = -1; - mList->numHwLayers = 2; - mList->flags = HWC_GEOMETRY_CHANGED; -#if ANDROID_VERSION >= 18 - mList->outbuf = nullptr; - mList->outbufAcquireFenceFd = -1; -#endif - mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; - mList->hwLayers[0].hints = 0; - /* Skip this layer so the hwc module doesn't complain about null handles */ - mList->hwLayers[0].flags = HWC_SKIP_LAYER; - mList->hwLayers[0].backgroundColor = {0}; - mList->hwLayers[0].acquireFenceFd = -1; - mList->hwLayers[0].releaseFenceFd = -1; - /* hwc module checks displayFrame even though it shouldn't */ - mList->hwLayers[0].displayFrame = r; - mList->hwLayers[1].compositionType = HWC_FRAMEBUFFER_TARGET; - mList->hwLayers[1].hints = 0; - mList->hwLayers[1].flags = 0; - mList->hwLayers[1].handle = buf; - mList->hwLayers[1].transform = 0; - mList->hwLayers[1].blending = HWC_BLENDING_NONE; -#if ANDROID_VERSION >= 19 - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) { - mList->hwLayers[1].sourceCropf.left = 0; - mList->hwLayers[1].sourceCropf.top = 0; - mList->hwLayers[1].sourceCropf.right = mWidth; - mList->hwLayers[1].sourceCropf.bottom = mHeight; - } else { - mList->hwLayers[1].sourceCrop = r; - } -#else - mList->hwLayers[1].sourceCrop = r; -#endif - mList->hwLayers[1].displayFrame = r; - mList->hwLayers[1].visibleRegionScreen.numRects = 1; - mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].displayFrame; - mList->hwLayers[1].acquireFenceFd = fence; - mList->hwLayers[1].releaseFenceFd = -1; -#if ANDROID_VERSION >= 18 - mList->hwLayers[1].planeAlpha = 0xFF; -#endif - mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); - int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); - - if (!mBootAnimDispSurface.get()) { - mDispSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd); - } else { - mBootAnimDispSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd); - } - - if (mList->retireFenceFd >= 0) - close(mList->retireFenceFd); - return !err; -} - -ANativeWindowBuffer* -GonkDisplayJB::DequeueBuffer() -{ - // Check for bootAnim or normal display flow. - sp<ANativeWindow> nativeWindow = - !mBootAnimSTClient.get() ? mSTClient : mBootAnimSTClient; - - ANativeWindowBuffer *buf; - int fenceFd = -1; - nativeWindow->dequeueBuffer(nativeWindow.get(), &buf, &fenceFd); - sp<Fence> fence(new Fence(fenceFd)); -#if ANDROID_VERSION == 17 - fence->waitForever(1000, "GonkDisplayJB_DequeueBuffer"); - // 1000 is what Android uses. It is a warning timeout in ms. - // This timeout was removed in ANDROID_VERSION 18. -#else - fence->waitForever("GonkDisplayJB_DequeueBuffer"); -#endif - return buf; -} - -bool -GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf) -{ - bool success = false; - int error = DoQueueBuffer(buf); - // Check for bootAnim or normal display flow. - if (!mBootAnimSTClient.get()) { - success = Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd()); - } else { - success = Post(mBootAnimDispSurface->lastHandle, mBootAnimDispSurface->GetPrevDispAcquireFd()); - } - return error == 0 && success; -} - -int -GonkDisplayJB::DoQueueBuffer(ANativeWindowBuffer* buf) -{ - int error = 0; - // Check for bootAnim or normal display flow. - if (!mBootAnimSTClient.get()) { - error = mSTClient->queueBuffer(mSTClient.get(), buf, -1); - } else { - error = mBootAnimSTClient->queueBuffer(mBootAnimSTClient.get(), buf, -1); - } - return error; -} - -void -GonkDisplayJB::UpdateDispSurface(EGLDisplay dpy, EGLSurface sur) -{ - if (sur != EGL_NO_SURFACE) { - eglSwapBuffers(dpy, sur); - } else { - // When BasicCompositor is used as Compositor, - // EGLSurface does not exit. - ANativeWindowBuffer* buf = DequeueBuffer(); - DoQueueBuffer(buf); - } -} - -void -GonkDisplayJB::NotifyBootAnimationStopped() -{ - if (mBootAnimSTClient.get()) { - mBootAnimSTClient = nullptr; - mBootAnimDispSurface = nullptr; - } -} - -void -GonkDisplayJB::PowerOnDisplay(int aDpy) -{ - MOZ_ASSERT(mHwc); -#if ANDROID_VERSION >= 21 - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) { - mHwc->setPowerMode(mHwc, aDpy, HWC_POWER_MODE_NORMAL); - } else { - mHwc->blank(mHwc, aDpy, 0); - } -#else - mHwc->blank(mHwc, aDpy, 0); -#endif -} - -GonkDisplay::NativeData -GonkDisplayJB::GetNativeData(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink) -{ - NativeData data; - - if (aDisplayType == DISPLAY_PRIMARY) { - data.mNativeWindow = mSTClient; - data.mDisplaySurface = mDispSurface; - data.mXdpi = xdpi; - } else if (aDisplayType == DISPLAY_EXTERNAL) { - int32_t values[3]; - const uint32_t attrs[] = { - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_NO_ATTRIBUTE - }; - mHwc->getDisplayAttributes(mHwc, aDisplayType, 0, attrs, values); - int width = values[0]; - int height = values[1]; - // FIXME!! values[2] returns 0 for external display, which doesn't - // sound right, Bug 1169176 is the follow-up bug for this issue. - data.mXdpi = values[2] ? values[2] / 1000.f : DEFAULT_XDPI; - PowerOnDisplay(HWC_DISPLAY_EXTERNAL); - CreateFramebufferSurface(data.mNativeWindow, - data.mDisplaySurface, - width, - height); - } else if (aDisplayType == DISPLAY_VIRTUAL) { - data.mXdpi = xdpi; - CreateVirtualDisplaySurface(aSink, - data.mNativeWindow, - data.mDisplaySurface); - } - - return data; -} - -__attribute__ ((visibility ("default"))) -GonkDisplay* -GetGonkDisplay() -{ - if (!sGonkDisplay) - sGonkDisplay = new GonkDisplayJB(); - return sGonkDisplay; -} - -} // namespace mozilla diff --git a/widget/gonk/libdisplay/GonkDisplayJB.h b/widget/gonk/libdisplay/GonkDisplayJB.h deleted file mode 100644 index 60bcdffc4..000000000 --- a/widget/gonk/libdisplay/GonkDisplayJB.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GONKDISPLAYJB_H -#define GONKDISPLAYJB_H - -#include "DisplaySurface.h" -#include "GonkDisplay.h" -#include "hardware/hwcomposer.h" -#include "hardware/power.h" -#include "ui/Fence.h" -#include "utils/RefBase.h" - -namespace mozilla { - -class MOZ_EXPORT GonkDisplayJB : public GonkDisplay { -public: - GonkDisplayJB(); - ~GonkDisplayJB(); - - virtual void SetEnabled(bool enabled); - - virtual void OnEnabled(OnEnabledCallbackType callback); - - virtual void* GetHWCDevice(); - - virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur); - - virtual ANativeWindowBuffer* DequeueBuffer(); - - virtual bool QueueBuffer(ANativeWindowBuffer* buf); - - virtual void UpdateDispSurface(EGLDisplay dpy, EGLSurface sur); - - bool Post(buffer_handle_t buf, int fence); - - virtual NativeData GetNativeData( - GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink = nullptr); - - virtual void NotifyBootAnimationStopped(); - -private: - void CreateFramebufferSurface(android::sp<ANativeWindow>& aNativeWindow, - android::sp<android::DisplaySurface>& aDisplaySurface, - uint32_t aWidth, uint32_t aHeight); - void CreateVirtualDisplaySurface(android::IGraphicBufferProducer* aSink, - android::sp<ANativeWindow>& aNativeWindow, - android::sp<android::DisplaySurface>& aDisplaySurface); - - void PowerOnDisplay(int aDpy); - - int DoQueueBuffer(ANativeWindowBuffer* buf); - - hw_module_t const* mModule; - hw_module_t const* mFBModule; - hwc_composer_device_1_t* mHwc; - framebuffer_device_t* mFBDevice; - power_module_t* mPowerModule; - android::sp<android::DisplaySurface> mDispSurface; - android::sp<ANativeWindow> mSTClient; - android::sp<android::DisplaySurface> mBootAnimDispSurface; - android::sp<ANativeWindow> mBootAnimSTClient; - android::sp<android::IGraphicBufferAlloc> mAlloc; - hwc_display_contents_1_t* mList; - uint32_t mWidth; - uint32_t mHeight; - OnEnabledCallbackType mEnabledCallback; -}; - -} - -#endif /* GONKDISPLAYJB_H */ diff --git a/widget/gonk/libdisplay/GraphicBufferAlloc.cpp b/widget/gonk/libdisplay/GraphicBufferAlloc.cpp deleted file mode 100644 index 5722b7fe3..000000000 --- a/widget/gonk/libdisplay/GraphicBufferAlloc.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - ** - ** Copyright 2012 The Android Open Source Project - ** - ** 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. - */ - -#include <cutils/log.h> - -#include <ui/GraphicBuffer.h> - -#include "GraphicBufferAlloc.h" - -// ---------------------------------------------------------------------------- -namespace android { -// ---------------------------------------------------------------------------- - -GraphicBufferAlloc::GraphicBufferAlloc() { -} - -GraphicBufferAlloc::~GraphicBufferAlloc() { -} - -sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { - sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(w, h, format, usage)); - status_t err = graphicBuffer->initCheck(); - *error = err; - if (err != 0 || graphicBuffer->handle == 0) { - if (err == NO_MEMORY) { - GraphicBuffer::dumpAllocationsToSystemLog(); - } - ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " - "failed (%s), handle=%p", - w, h, strerror(-err), graphicBuffer->handle); - return 0; - } - return graphicBuffer; -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- diff --git a/widget/gonk/libdisplay/GraphicBufferAlloc.h b/widget/gonk/libdisplay/GraphicBufferAlloc.h deleted file mode 100644 index b08750c2f..000000000 --- a/widget/gonk/libdisplay/GraphicBufferAlloc.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H -#define ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H - -#include <stdint.h> -#include <sys/types.h> - -#include <gui/IGraphicBufferAlloc.h> -#include <ui/PixelFormat.h> -#include <utils/Errors.h> - -namespace android { -// --------------------------------------------------------------------------- - -class GraphicBuffer; - -class GraphicBufferAlloc : public BnGraphicBufferAlloc { -public: - GraphicBufferAlloc(); - virtual ~GraphicBufferAlloc(); - virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error); -}; - - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H diff --git a/widget/gonk/libdisplay/VirtualDisplaySurface.cpp b/widget/gonk/libdisplay/VirtualDisplaySurface.cpp deleted file mode 100644 index 746707885..000000000 --- a/widget/gonk/libdisplay/VirtualDisplaySurface.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * 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. - */ - -// #define LOG_NDEBUG 0 -#include "VirtualDisplaySurface.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -#if defined(FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS) -static const bool sForceHwcCopy = true; -#else -static const bool sForceHwcCopy = false; -#endif - -#define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ - mDisplayName.string(), ##__VA_ARGS__) -#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ - mDisplayName.string(), ##__VA_ARGS__) -#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \ - mDisplayName.string(), ##__VA_ARGS__) - -__attribute__((unused)) -static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) { - switch (type) { - case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN"; - case DisplaySurface::COMPOSITION_GLES: return "GLES"; - case DisplaySurface::COMPOSITION_HWC: return "HWC"; - case DisplaySurface::COMPOSITION_MIXED: return "MIXED"; - default: return "<INVALID>"; - } -} - -VirtualDisplaySurface::VirtualDisplaySurface(int32_t dispId, - const sp<IGraphicBufferProducer>& sink, - const sp<IGraphicBufferProducer>& bqProducer, - const sp<StreamConsumer>& bqConsumer, - const String8& name) -: DisplaySurface(bqConsumer), - mDisplayId(dispId), - mDisplayName(name), - mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), - mProducerSlotSource(0), - mDbgState(DBG_STATE_IDLE), - mDbgLastCompositionType(COMPOSITION_UNKNOWN), - mMustRecompose(false) -{ - mSource[SOURCE_SINK] = sink; - mSource[SOURCE_SCRATCH] = bqProducer; - - resetPerFrameState(); - - int sinkWidth, sinkHeight; - sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth); - sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); - mSinkBufferWidth = sinkWidth; - mSinkBufferHeight = sinkHeight; - - // Pick the buffer format to request from the sink when not rendering to it - // with GLES. If the consumer needs CPU access, use the default format - // set by the consumer. Otherwise allow gralloc to decide the format based - // on usage bits. - int sinkUsage; - sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage); - if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { - int sinkFormat; - sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat); - mDefaultOutputFormat = sinkFormat; - } else { - mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; - } - mOutputFormat = mDefaultOutputFormat; - - ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); - mConsumer->setConsumerName(ConsumerBase::mName); - mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); - mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); - mConsumer->setDefaultMaxBufferCount(2); -} - -VirtualDisplaySurface::~VirtualDisplaySurface() { -} - -status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { - if (mDisplayId < 0) - return NO_ERROR; - - mMustRecompose = mustRecompose; - - VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, - "Unexpected beginFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_BEGUN; - - return refreshOutputBuffer(); -} - -status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { - if (mDisplayId < 0) - return NO_ERROR; - - VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN, - "Unexpected prepareFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_PREPARED; - - mCompositionType = compositionType; - if (sForceHwcCopy && mCompositionType == COMPOSITION_GLES) { - // Some hardware can do RGB->YUV conversion more efficiently in hardware - // controlled by HWC than in hardware controlled by the video encoder. - // Forcing GLES-composed frames to go through an extra copy by the HWC - // allows the format conversion to happen there, rather than passing RGB - // directly to the consumer. - // - // On the other hand, when the consumer prefers RGB or can consume RGB - // inexpensively, this forces an unnecessary copy. - mCompositionType = COMPOSITION_MIXED; - } - - if (mCompositionType != mDbgLastCompositionType) { - VDS_LOGV("prepareFrame: composition type changed to %s", - dbgCompositionTypeStr(mCompositionType)); - mDbgLastCompositionType = mCompositionType; - } - - if (mCompositionType != COMPOSITION_GLES && - (mOutputFormat != mDefaultOutputFormat || - mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { - // We must have just switched from GLES-only to MIXED or HWC - // composition. Stop using the format and usage requested by the GLES - // driver; they may be suboptimal when HWC is writing to the output - // buffer. For example, if the output is going to a video encoder, and - // HWC can write directly to YUV, some hardware can skip a - // memory-to-memory RGB-to-YUV conversion step. - // - // If we just switched *to* GLES-only mode, we'll change the - // format/usage and get a new buffer when the GLES driver calls - // dequeueBuffer(). - mOutputFormat = mDefaultOutputFormat; - mOutputUsage = GRALLOC_USAGE_HW_COMPOSER; - refreshOutputBuffer(); - } - - return NO_ERROR; -} - -status_t VirtualDisplaySurface::compositionComplete() { - return NO_ERROR; -} - -status_t VirtualDisplaySurface::advanceFrame() { - return NO_ERROR; - -// XXX Add HWC support - -#if 0 - if (mDisplayId < 0) - return NO_ERROR; - - if (mCompositionType == COMPOSITION_HWC) { - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected advanceFrame() in %s state on HWC frame", - dbgStateStr()); - } else { - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE, - "Unexpected advanceFrame() in %s state on GLES/MIXED frame", - dbgStateStr()); - } - mDbgState = DBG_STATE_HWC; - - if (mOutputProducerSlot < 0 || - (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) { - // Last chance bailout if something bad happened earlier. For example, - // in a GLES configuration, if the sink disappears then dequeueBuffer - // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger - // will soldier on. So we end up here without a buffer. There should - // be lots of scary messages in the log just before this. - VDS_LOGE("advanceFrame: no buffer, bailing out"); - return NO_MEMORY; - } - - sp<GraphicBuffer> fbBuffer = mFbProducerSlot >= 0 ? - mProducerBuffers[mFbProducerSlot] : sp<GraphicBuffer>(NULL); - sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot]; - VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)", - mFbProducerSlot, fbBuffer.get(), - mOutputProducerSlot, outBuffer.get()); - - // At this point we know the output buffer acquire fence, - // so update HWC state with it. - mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer); - - status_t result = NO_ERROR; - if (fbBuffer != NULL) { - result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); - } - - return result; -#endif -} - -void VirtualDisplaySurface::onFrameCommitted() { - return; - -// XXX Add HWC support - -#if 0 - if (mDisplayId < 0) - return; - - VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, - "Unexpected onFrameCommitted() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_IDLE; - - sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId); - if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { - // release the scratch buffer back to the pool - Mutex::Autolock lock(mMutex); - int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); - VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); - addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); - releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - } - - if (mOutputProducerSlot >= 0) { - int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); - QueueBufferOutput qbo; - sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId); - VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); - if (mMustRecompose) { - status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, - QueueBufferInput( - systemTime(), false /* isAutoTimestamp */, - Rect(mSinkBufferWidth, mSinkBufferHeight), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, - true /* async*/, - outFence), - &qbo); - if (result == NO_ERROR) { - updateQueueBufferOutput(qbo); - } - } else { - // If the surface hadn't actually been updated, then we only went - // through the motions of updating the display to keep our state - // machine happy. We cancel the buffer to avoid triggering another - // re-composition and causing an infinite loop. - mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence); - } - } - - resetPerFrameState(); -#endif -} - -void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) { - uint32_t tmpW, tmpH, transformHint, numPendingBuffers; - mQueueBufferOutput.deflate(&tmpW, &tmpH, &transformHint, &numPendingBuffers); - mQueueBufferOutput.inflate(w, h, transformHint, numPendingBuffers); - - mSinkBufferWidth = w; - mSinkBufferHeight = h; -} - -status_t VirtualDisplaySurface::requestBuffer(int pslot, - sp<GraphicBuffer>* outBuf) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); - - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, - "Unexpected requestBuffer pslot=%d in %s state", - pslot, dbgStateStr()); - - *outBuf = mProducerBuffers[pslot]; - return NO_ERROR; -} - -status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { - return mSource[SOURCE_SINK]->setBufferCount(bufferCount); -} - -status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, uint32_t usage, int* sslot, sp<Fence>* fence) { - LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); - // Don't let a slow consumer block us - bool async = (source == SOURCE_SINK); - - status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, - mSinkBufferWidth, mSinkBufferHeight, format, usage); - if (result < 0) - return result; - int pslot = mapSource2ProducerSlot(source, *sslot); - VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d", - dbgSourceStr(source), *sslot, pslot, result); - uint64_t sourceBit = static_cast<uint64_t>(source) << pslot; - - if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) { - // This slot was previously dequeued from the other source; must - // re-request the buffer. - result |= BUFFER_NEEDS_REALLOCATION; - mProducerSlotSource &= ~(1ULL << pslot); - mProducerSlotSource |= sourceBit; - } - - if (result & RELEASE_ALL_BUFFERS) { - for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - if ((mProducerSlotSource & (1ULL << i)) == sourceBit) - mProducerBuffers[i].clear(); - } - } - if (result & BUFFER_NEEDS_REALLOCATION) { - result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]); - if (result < 0) { - mProducerBuffers[pslot].clear(); - mSource[source]->cancelBuffer(*sslot, *fence); - return result; - } - VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x", - dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), - mProducerBuffers[pslot]->getPixelFormat(), - mProducerBuffers[pslot]->getUsage()); - } - - return result; -} - -status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage); - - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected dequeueBuffer() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_GLES; - - VDS_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)"); - VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); - - status_t result = NO_ERROR; - Source source = fbSourceForCompositionType(mCompositionType); - - if (source == SOURCE_SINK) { - - if (mOutputProducerSlot < 0) { - // Last chance bailout if something bad happened earlier. For example, - // in a GLES configuration, if the sink disappears then dequeueBuffer - // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger - // will soldier on. So we end up here without a buffer. There should - // be lots of scary messages in the log just before this. - VDS_LOGE("dequeueBuffer: no buffer, bailing out"); - return NO_MEMORY; - } - - // We already dequeued the output buffer. If the GLES driver wants - // something incompatible, we have to cancel and get a new one. This - // will mean that HWC will see a different output buffer between - // prepare and set, but since we're in GLES-only mode already it - // shouldn't matter. - - usage |= GRALLOC_USAGE_HW_COMPOSER; - const sp<GraphicBuffer>& buf = mProducerBuffers[mOutputProducerSlot]; - if ((usage & ~buf->getUsage()) != 0 || - (format != 0 && format != (uint32_t)buf->getPixelFormat()) || - (w != 0 && w != mSinkBufferWidth) || - (h != 0 && h != mSinkBufferHeight)) { - VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " - "want %dx%d fmt=%d use=%#x, " - "have %dx%d fmt=%d use=%#x", - w, h, format, usage, - mSinkBufferWidth, mSinkBufferHeight, - buf->getPixelFormat(), buf->getUsage()); - mOutputFormat = format; - mOutputUsage = usage; - result = refreshOutputBuffer(); - if (result < 0) - return result; - } - } - - if (source == SOURCE_SINK) { - *pslot = mOutputProducerSlot; - *fence = mOutputFence; - } else { - int sslot; - result = dequeueBuffer(source, format, usage, &sslot, fence); - if (result >= 0) { - *pslot = mapSource2ProducerSlot(source, sslot); - } - } - return result; -} - -status_t VirtualDisplaySurface::detachBuffer(int /* slot */) { - VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; -} - -status_t VirtualDisplaySurface::detachNextBuffer( - sp<GraphicBuffer>* /* outBuffer */, sp<Fence>* /* outFence */) { - VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; -} - -status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */, - const sp<GraphicBuffer>& /* buffer */) { - VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; -} - -status_t VirtualDisplaySurface::queueBuffer(int pslot, - const QueueBufferInput& input, QueueBufferOutput* output) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); - - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, - "Unexpected queueBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - mDbgState = DBG_STATE_GLES_DONE; - - VDS_LOGV("queueBuffer pslot=%d", pslot); - - status_t result; - if (mCompositionType == COMPOSITION_MIXED) { - // Queue the buffer back into the scratch pool - QueueBufferOutput scratchQBO; - int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); - result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO); - if (result != NO_ERROR) - return result; - - // Now acquire the buffer from the scratch pool -- should be the same - // slot and fence as we just queued. - Mutex::Autolock lock(mMutex); - BufferQueue::BufferItem item; - result = acquireBufferLocked(&item, 0); - if (result != NO_ERROR) - return result; - VDS_LOGW_IF(item.mBuf != sslot, - "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", - item.mBuf, sslot); - mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf); - mFbFence = mSlots[item.mBuf].mFence; - - } else { - LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES, - "Unexpected queueBuffer in state %s for compositionType %s", - dbgStateStr(), dbgCompositionTypeStr(mCompositionType)); - - // Extract the GLES release fence for HWC to acquire - int64_t timestamp; - bool isAutoTimestamp; - Rect crop; - int scalingMode; - uint32_t transform; - bool async; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, - &transform, &async, &mFbFence); - - mFbProducerSlot = pslot; - mOutputFence = mFbFence; - } - - *output = mQueueBufferOutput; - return NO_ERROR; -} - -void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); - - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, - "Unexpected cancelBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - VDS_LOGV("cancelBuffer pslot=%d", pslot); - Source source = fbSourceForCompositionType(mCompositionType); - return mSource[source]->cancelBuffer( - mapProducer2SourceSlot(source, pslot), fence); -} - -int VirtualDisplaySurface::query(int what, int* value) { - switch (what) { - case NATIVE_WINDOW_WIDTH: - *value = mSinkBufferWidth; - break; - case NATIVE_WINDOW_HEIGHT: - *value = mSinkBufferHeight; - break; - default: - return mSource[SOURCE_SINK]->query(what, value); - } - return NO_ERROR; -} - -#if ANDROID_VERSION >= 21 -status_t VirtualDisplaySurface::connect(const sp<IProducerListener>& listener, - int api, bool producerControlledByApp, - QueueBufferOutput* output) { - QueueBufferOutput qbo; - status_t result = mSource[SOURCE_SINK]->connect(listener, api, - producerControlledByApp, &qbo); - if (result == NO_ERROR) { - updateQueueBufferOutput(qbo); - *output = mQueueBufferOutput; - } - return result; -} -#else -status_t VirtualDisplaySurface::connect(const sp<IBinder>& token, - int api, bool producerControlledByApp, - QueueBufferOutput* output) { - QueueBufferOutput qbo; - status_t result = mSource[SOURCE_SINK]->connect(token, api, producerControlledByApp, &qbo); - if (result == NO_ERROR) { - updateQueueBufferOutput(qbo); - *output = mQueueBufferOutput; - } - return result; -} -#endif - -status_t VirtualDisplaySurface::disconnect(int api) { - return mSource[SOURCE_SINK]->disconnect(api); -} - -#if ANDROID_VERSION >= 21 -status_t VirtualDisplaySurface::setSidebandStream(const sp<NativeHandle>& /*stream*/) { - return INVALID_OPERATION; -} -#endif - -void VirtualDisplaySurface::allocateBuffers(bool /* async */, - uint32_t /* width */, uint32_t /* height */, uint32_t /* format */, - uint32_t /* usage */) { - // TODO: Should we actually allocate buffers for a virtual display? -} - -void VirtualDisplaySurface::updateQueueBufferOutput( - const QueueBufferOutput& qbo) { - uint32_t w, h, transformHint, numPendingBuffers; - qbo.deflate(&w, &h, &transformHint, &numPendingBuffers); - mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers); -} - -void VirtualDisplaySurface::resetPerFrameState() { - mCompositionType = COMPOSITION_UNKNOWN; - mFbFence = Fence::NO_FENCE; - mOutputFence = Fence::NO_FENCE; - mOutputProducerSlot = -1; - mFbProducerSlot = -1; -} - -status_t VirtualDisplaySurface::refreshOutputBuffer() { - - return INVALID_OPERATION; - -// XXX Add HWC support - -#if 0 - if (mOutputProducerSlot >= 0) { - mSource[SOURCE_SINK]->cancelBuffer( - mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot), - mOutputFence); - } - - int sslot; - status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage, - &sslot, &mOutputFence); - if (result < 0) - return result; - mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); - - // On GLES-only frames, we don't have the right output buffer acquire fence - // until after GLES calls queueBuffer(). So here we just set the buffer - // (for use in HWC prepare) but not the fence; we'll call this again with - // the proper fence once we have it. - result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE, - mProducerBuffers[mOutputProducerSlot]); - - return result; -#endif -} - -// This slot mapping function is its own inverse, so two copies are unnecessary. -// Both are kept to make the intent clear where the function is called, and for -// the (unlikely) chance that we switch to a different mapping function. -int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) { - if (source == SOURCE_SCRATCH) { - return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1; - } else { - return sslot; - } -} -int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) { - return mapSource2ProducerSlot(source, pslot); -} - -VirtualDisplaySurface::Source -VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) { - return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK; -} - -const char* VirtualDisplaySurface::dbgStateStr() const { - switch (mDbgState) { - case DBG_STATE_IDLE: return "IDLE"; - case DBG_STATE_PREPARED: return "PREPARED"; - case DBG_STATE_GLES: return "GLES"; - case DBG_STATE_GLES_DONE: return "GLES_DONE"; - case DBG_STATE_HWC: return "HWC"; - default: return "INVALID"; - } -} - -const char* VirtualDisplaySurface::dbgSourceStr(Source s) { - switch (s) { - case SOURCE_SINK: return "SINK"; - case SOURCE_SCRATCH: return "SCRATCH"; - default: return "INVALID"; - } -} - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- diff --git a/widget/gonk/libdisplay/VirtualDisplaySurface.h b/widget/gonk/libdisplay/VirtualDisplaySurface.h deleted file mode 100644 index 9125d8751..000000000 --- a/widget/gonk/libdisplay/VirtualDisplaySurface.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H -#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H - -#include <gui/IGraphicBufferProducer.h> - -#include "DisplaySurface.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -class HWComposer; -class IProducerListener; - -/* This DisplaySurface implementation supports virtual displays, where GLES - * and/or HWC compose into a buffer that is then passed to an arbitrary - * consumer (the sink) running in another process. - * - * The simplest case is when the virtual display will never use the h/w - * composer -- either the h/w composer doesn't support writing to buffers, or - * there are more virtual displays than it supports simultaneously. In this - * case, the GLES driver works directly with the output buffer queue, and - * calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do - * nothing. - * - * If h/w composer might be used, then each frame will fall into one of three - * configurations: GLES-only, HWC-only, and MIXED composition. In all of these, - * we must provide a FB target buffer and output buffer for the HWC set() call. - * - * In GLES-only composition, the GLES driver is given a buffer from the sink to - * render into. When the GLES driver queues the buffer to the - * VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of - * immediately queueing it to the sink. The buffer is used as both the FB - * target and output buffer for HWC, though on these frames the HWC doesn't - * do any work for this display and doesn't write to the output buffer. After - * composition is complete, the buffer is queued to the sink. - * - * In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from - * the sink and passes it to HWC as both the FB target buffer and output - * buffer. The HWC doesn't need to read from the FB target buffer, but does - * write to the output buffer. After composition is complete, the buffer is - * queued to the sink. - * - * On MIXED frames, things become more complicated, since some h/w composer - * implementations can't read from and write to the same buffer. This class has - * an internal BufferQueue that it uses as a scratch buffer pool. The GLES - * driver is given a scratch buffer to render into. When it finishes rendering, - * the buffer is queued and then immediately acquired by the - * VirtualDisplaySurface. The scratch buffer is then used as the FB target - * buffer for HWC, and a separate buffer is dequeued from the sink and used as - * the HWC output buffer. When HWC composition is complete, the scratch buffer - * is released and the output buffer is queued to the sink. - */ -class VirtualDisplaySurface : public DisplaySurface, - public BnGraphicBufferProducer { -public: - VirtualDisplaySurface(int32_t dispId, - const sp<IGraphicBufferProducer>& sink, - const sp<IGraphicBufferProducer>& bqProducer, - const sp<StreamConsumer>& bqConsumer, - const String8& name); - - // - // DisplaySurface interface - // - virtual status_t beginFrame(bool mustRecompose); - virtual status_t prepareFrame(CompositionType compositionType); - virtual status_t compositionComplete(); - virtual status_t advanceFrame(); - virtual void onFrameCommitted(); - virtual void resizeBuffers(const uint32_t w, const uint32_t h); - - virtual status_t setReleaseFenceFd(int fenceFd) { return INVALID_OPERATION; } - virtual int GetPrevDispAcquireFd() { return -1; }; - -private: - enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1}; - - virtual ~VirtualDisplaySurface(); - - // - // IGraphicBufferProducer interface, used by the GLES driver. - // - virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf); - virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - virtual status_t detachBuffer(int slot); - virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence); - virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer); - virtual status_t queueBuffer(int pslot, - const QueueBufferInput& input, QueueBufferOutput* output); - virtual void cancelBuffer(int pslot, const sp<Fence>& fence); - virtual int query(int what, int* value); -#if ANDROID_VERSION >= 21 - virtual status_t connect(const sp<IProducerListener>& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output); -#else - virtual status_t connect(const sp<IBinder>& token, - int api, bool producerControlledByApp, QueueBufferOutput* output); -#endif - virtual status_t disconnect(int api); -#if ANDROID_VERSION >= 21 - virtual status_t setSidebandStream(const sp<NativeHandle>& stream); -#endif - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); - - // - // Utility methods - // - static Source fbSourceForCompositionType(CompositionType type); - status_t dequeueBuffer(Source source, uint32_t format, uint32_t usage, - int* sslot, sp<Fence>* fence); - void updateQueueBufferOutput(const QueueBufferOutput& qbo); - void resetPerFrameState(); - status_t refreshOutputBuffer(); - - // Both the sink and scratch buffer pools have their own set of slots - // ("source slots", or "sslot"). We have to merge these into the single - // set of slots used by the GLES producer ("producer slots" or "pslot") and - // internally in the VirtualDisplaySurface. To minimize the number of times - // a producer slot switches which source it comes from, we map source slot - // numbers to producer slot numbers differently for each source. - static int mapSource2ProducerSlot(Source source, int sslot); - static int mapProducer2SourceSlot(Source source, int pslot); - - // - // Immutable after construction - // - const int32_t mDisplayId; - const String8 mDisplayName; - sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_* - uint32_t mDefaultOutputFormat; - - // - // Inter-frame state - // - - // To avoid buffer reallocations, we track the buffer usage and format - // we used on the previous frame and use it again on the new frame. If - // the composition type changes or the GLES driver starts requesting - // different usage/format, we'll get a new buffer. - uint32_t mOutputFormat; - uint32_t mOutputUsage; - - // Since we present a single producer interface to the GLES driver, but - // are internally muxing between the sink and scratch producers, we have - // to keep track of which source last returned each producer slot from - // dequeueBuffer. Each bit in mProducerSlotSource corresponds to a producer - // slot. Both mProducerSlotSource and mProducerBuffers are indexed by a - // "producer slot"; see the mapSlot*() functions. - uint64_t mProducerSlotSource; - sp<GraphicBuffer> mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS]; - - // The QueueBufferOutput with the latest info from the sink, and with the - // transform hint cleared. Since we defer queueBuffer from the GLES driver - // to the sink, we have to return the previous version. - QueueBufferOutput mQueueBufferOutput; - - // Details of the current sink buffer. These become valid when a buffer is - // dequeued from the sink, and are used when queueing the buffer. - uint32_t mSinkBufferWidth, mSinkBufferHeight; - - // - // Intra-frame state - // - - // Composition type and GLES buffer source for the current frame. - // Valid after prepareFrame(), cleared in onFrameCommitted. - CompositionType mCompositionType; - - // mFbFence is the fence HWC should wait for before reading the framebuffer - // target buffer. - sp<Fence> mFbFence; - - // mOutputFence is the fence HWC should wait for before writing to the - // output buffer. - sp<Fence> mOutputFence; - - // Producer slot numbers for the buffers to use for HWC framebuffer target - // and output. - int mFbProducerSlot; - int mOutputProducerSlot; - - // Debug only -- track the sequence of events in each frame so we can make - // sure they happen in the order we expect. This class implicitly models - // a state machine; this enum/variable makes it explicit. - // - // +-----------+-------------------+-------------+ - // | State | Event || Next State | - // +-----------+-------------------+-------------+ - // | IDLE | beginFrame || BEGUN | - // | BEGUN | prepareFrame || PREPARED | - // | PREPARED | dequeueBuffer [1] || GLES | - // | PREPARED | advanceFrame [2] || HWC | - // | GLES | queueBuffer || GLES_DONE | - // | GLES_DONE | advanceFrame || HWC | - // | HWC | onFrameCommitted || IDLE | - // +-----------+-------------------++------------+ - // [1] COMPOSITION_GLES and COMPOSITION_MIXED frames. - // [2] COMPOSITION_HWC frames. - // - enum DbgState { - // no buffer dequeued, don't know anything about the next frame - DBG_STATE_IDLE, - // output buffer dequeued, framebuffer source not yet known - DBG_STATE_BEGUN, - // output buffer dequeued, framebuffer source known but not provided - // to GLES yet. - DBG_STATE_PREPARED, - // GLES driver has a buffer dequeued - DBG_STATE_GLES, - // GLES driver has queued the buffer, we haven't sent it to HWC yet - DBG_STATE_GLES_DONE, - // HWC has the buffer for this frame - DBG_STATE_HWC, - }; - DbgState mDbgState; - CompositionType mDbgLastCompositionType; - - const char* dbgStateStr() const; - static const char* dbgSourceStr(Source s); - - bool mMustRecompose; -}; - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H - diff --git a/widget/gonk/libdisplay/moz.build b/widget/gonk/libdisplay/moz.build deleted file mode 100644 index 917320592..000000000 --- a/widget/gonk/libdisplay/moz.build +++ /dev/null @@ -1,59 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -SOURCES += [ - 'BootAnimation.cpp', -] - -if CONFIG['ANDROID_VERSION'] >= '19': - SOURCES += [ - 'FramebufferSurface.cpp', - 'GonkDisplayJB.cpp', - 'VirtualDisplaySurface.cpp', - ] -elif CONFIG['ANDROID_VERSION'] == '18': - SOURCES += [ - 'FramebufferSurface.cpp', - 'GonkDisplayJB.cpp', - ] -elif CONFIG['ANDROID_VERSION'] == '17': - SOURCES += [ - 'FramebufferSurface.cpp', - 'GonkDisplayJB.cpp', - 'GraphicBufferAlloc.cpp', - ] -elif CONFIG['ANDROID_VERSION'] and CONFIG['COMPILE_ENVIRONMENT']: - error('Unsupported platform version: %s' % (CONFIG['ANDROID_VERSION'])) - -Library('display') - -include('/ipc/chromium/chromium-config.mozbuild') - -FORCE_STATIC_LIB = True - -DEFINES['XPCOM_GLUE'] = True - -DISABLE_STL_WRAPPING = True - -LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/include/gui', - 'frameworks/native/opengl/include', - 'hardware/libhardware/include', - 'hardware/libhardware_legacy/include', - 'system/core/libsuspend/include', - ] -] diff --git a/widget/gonk/libui/EventHub.cpp b/widget/gonk/libui/EventHub.cpp deleted file mode 100644 index 9da29bbeb..000000000 --- a/widget/gonk/libui/EventHub.cpp +++ /dev/null @@ -1,1549 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "EventHub" - -// #define LOG_NDEBUG 0 -#include "cutils_log.h" - -#include "EventHub.h" - -#include <hardware_legacy/power.h> - -#include <cutils/properties.h> -#include "cutils_log.h" -#include <utils/Timers.h> -#include <utils/threads.h> -#include <utils/Errors.h> - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <fcntl.h> -#include <memory.h> -#include <errno.h> -#include <assert.h> - -#include "KeyLayoutMap.h" -#include "KeyCharacterMap.h" -#include "VirtualKeyMap.h" - -#include <string.h> -#include <stdint.h> -#include <dirent.h> - -#include <sys/inotify.h> -#include <sys/epoll.h> -#include <sys/ioctl.h> -#include <sys/limits.h> -#include "sha1.h" - -/* this macro is used to tell if "bit" is set in "array" - * it selects a byte from the array, and does a boolean AND - * operation with a byte that only has the relevant bit set. - * eg. to check for the 12th bit, we do (array[1] & 1<<4) - */ -#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) - -/* this macro computes the number of bytes needed to represent a bit array of the specified size */ -#define sizeof_bit_array(bits) ((bits + 7) / 8) - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " - -namespace android { - -static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *DEVICE_PATH = "/dev/input"; - -/* return the larger integer */ -static inline int max(int v1, int v2) -{ - return (v1 > v2) ? v1 : v2; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static String8 sha1(const String8& in) { - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size()); - u_char digest[SHA1_DIGEST_LENGTH]; - SHA1Final(digest, &ctx); - - String8 out; - for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) { - out.appendFormat("%02x", digest[i]); - } - return out; -} - -static void setDescriptor(InputDeviceIdentifier& identifier) { - // Compute a device descriptor that uniquely identifies the device. - // The descriptor is assumed to be a stable identifier. Its value should not - // change between reboots, reconnections, firmware updates or new releases of Android. - // Ideally, we also want the descriptor to be short and relatively opaque. - String8 rawDescriptor; - rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product); - if (!identifier.uniqueId.isEmpty()) { - rawDescriptor.append("uniqueId:"); - rawDescriptor.append(identifier.uniqueId); - } if (identifier.vendor == 0 && identifier.product == 0) { - // If we don't know the vendor and product id, then the device is probably - // built-in so we need to rely on other information to uniquely identify - // the input device. Usually we try to avoid relying on the device name or - // location but for built-in input device, they are unlikely to ever change. - if (!identifier.name.isEmpty()) { - rawDescriptor.append("name:"); - rawDescriptor.append(identifier.name); - } else if (!identifier.location.isEmpty()) { - rawDescriptor.append("location:"); - rawDescriptor.append(identifier.location); - } - } - identifier.descriptor = sha1(rawDescriptor); - ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(), - identifier.descriptor.string()); -} - -// --- Global Functions --- - -uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { - // Touch devices get dibs on touch-related axes. - if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { - switch (axis) { - case ABS_X: - case ABS_Y: - case ABS_PRESSURE: - case ABS_TOOL_WIDTH: - case ABS_DISTANCE: - case ABS_TILT_X: - case ABS_TILT_Y: - case ABS_MT_SLOT: - case ABS_MT_TOUCH_MAJOR: - case ABS_MT_TOUCH_MINOR: - case ABS_MT_WIDTH_MAJOR: - case ABS_MT_WIDTH_MINOR: - case ABS_MT_ORIENTATION: - case ABS_MT_POSITION_X: - case ABS_MT_POSITION_Y: - case ABS_MT_TOOL_TYPE: - case ABS_MT_BLOB_ID: - case ABS_MT_TRACKING_ID: - case ABS_MT_PRESSURE: - case ABS_MT_DISTANCE: - return INPUT_DEVICE_CLASS_TOUCH; - } - } - - // Joystick devices get the rest. - return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; -} - -// --- EventHub::Device --- - -EventHub::Device::Device(int fd, int32_t id, const String8& path, - const InputDeviceIdentifier& identifier) : - next(NULL), - fd(fd), id(id), path(path), identifier(identifier), - classes(0), configuration(NULL), virtualKeyMap(NULL), - ffEffectPlaying(false), ffEffectId(-1), - timestampOverrideSec(0), timestampOverrideUsec(0) { - memset(keyBitmask, 0, sizeof(keyBitmask)); - memset(absBitmask, 0, sizeof(absBitmask)); - memset(relBitmask, 0, sizeof(relBitmask)); - memset(swBitmask, 0, sizeof(swBitmask)); - memset(ledBitmask, 0, sizeof(ledBitmask)); - memset(ffBitmask, 0, sizeof(ffBitmask)); - memset(propBitmask, 0, sizeof(propBitmask)); -} - -EventHub::Device::~Device() { - close(); - delete configuration; - delete virtualKeyMap; -} - -void EventHub::Device::close() { - if (fd >= 0) { - ::close(fd); - fd = -1; - } -} - - -// --- EventHub --- - -const uint32_t EventHub::EPOLL_ID_INOTIFY; -const uint32_t EventHub::EPOLL_ID_WAKE; -const int EventHub::EPOLL_SIZE_HINT; -const int EventHub::EPOLL_MAX_EVENTS; - -EventHub::EventHub(void) : - mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), - mOpeningDevices(0), mClosingDevices(0), - mNeedToSendFinishedDeviceScan(false), - mNeedToReopenDevices(false), mNeedToScanDevices(true), - mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - - mEpollFd = epoll_create(EPOLL_SIZE_HINT); - LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); - - mINotifyFd = inotify_init(); - int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); - LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d", - DEVICE_PATH, errno); - - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - eventItem.data.u32 = EPOLL_ID_INOTIFY; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno); - - int wakeFds[2]; - result = pipe(wakeFds); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); - - mWakeReadPipeFd = wakeFds[0]; - mWakeWritePipeFd = wakeFds[1]; - - result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); - - result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); - - eventItem.data.u32 = EPOLL_ID_WAKE; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); -} - -EventHub::~EventHub(void) { - closeAllDevicesLocked(); - - while (mClosingDevices) { - Device* device = mClosingDevices; - mClosingDevices = device->next; - delete device; - } - - ::close(mEpollFd); - ::close(mINotifyFd); - ::close(mWakeReadPipeFd); - ::close(mWakeWritePipeFd); - - release_wake_lock(WAKE_LOCK_ID); -} - -InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return InputDeviceIdentifier(); - return device->identifier; -} - -uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return 0; - return device->classes; -} - -void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->configuration) { - *outConfiguration = *device->configuration; - } else { - outConfiguration->clear(); - } -} - -status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { - outAxisInfo->clear(); - - if (axis >= 0 && axis <= ABS_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { - struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.string(), device->fd, errno); - return -errno; - } - - if (info.minimum != info.maximum) { - outAxisInfo->valid = true; - outAxisInfo->minValue = info.minimum; - outAxisInfo->maxValue = info.maximum; - outAxisInfo->flat = info.flat; - outAxisInfo->fuzz = info.fuzz; - outAxisInfo->resolution = info.resolution; - } - return OK; - } - } - return -1; -} - -bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const { - if (axis >= 0 && axis <= REL_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device) { - return test_bit(axis, device->relBitmask); - } - } - return false; -} - -bool EventHub::hasInputProperty(int32_t deviceId, int property) const { - if (property >= 0 && property <= INPUT_PROP_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device) { - return test_bit(property, device->propBitmask); - } - } - return false; -} - -int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { - if (scanCode >= 0 && scanCode <= KEY_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { - uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; - memset(keyState, 0, sizeof(keyState)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { - return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { - Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); - if (scanCodes.size() != 0) { - uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; - memset(keyState, 0, sizeof(keyState)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { - for (size_t i = 0; i < scanCodes.size(); i++) { - int32_t sc = scanCodes.itemAt(i); - if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) { - return AKEY_STATE_DOWN; - } - } - return AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { - if (sw >= 0 && sw <= SW_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { - uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; - memset(swState, 0, sizeof(swState)); - if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { - return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { - *outValue = 0; - - if (axis >= 0 && axis <= ABS_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { - struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.string(), device->fd, errno); - return -errno; - } - - *outValue = info.value; - return OK; - } - } - return -1; -} - -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && device->keyMap.haveKeyLayout()) { - Vector<int32_t> scanCodes; - for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { - scanCodes.clear(); - - status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( - keyCodes[codeIndex], &scanCodes); - if (! err) { - // check the possible scan codes identified by the layout map against the - // map of codes actually emitted by the driver - for (size_t sc = 0; sc < scanCodes.size(); sc++) { - if (test_bit(scanCodes[sc], device->keyBitmask)) { - outFlags[codeIndex] = 1; - break; - } - } - } - } - return true; - } - return false; -} - -status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device) { - // Check the key character map first. - sp<KeyCharacterMap> kcm = device->getKeyCharacterMap(); - if (kcm != NULL) { - if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { - *outFlags = 0; - return NO_ERROR; - } - } - - // Check the key layout next. - if (device->keyMap.haveKeyLayout()) { - if (!device->keyMap.keyLayoutMap->mapKey( - scanCode, usageCode, outKeycode, outFlags)) { - return NO_ERROR; - } - } - } - - *outKeycode = 0; - *outFlags = 0; - return NAME_NOT_FOUND; -} - -status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo); - if (err == NO_ERROR) { - return NO_ERROR; - } - } - - return NAME_NOT_FOUND; -} - -void EventHub::setExcludedDevices(const Vector<String8>& devices) { - AutoMutex _l(mLock); - - mExcludedDevices = devices; -} - -bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && scanCode >= 0 && scanCode <= KEY_MAX) { - if (test_bit(scanCode, device->keyBitmask)) { - return true; - } - } - return false; -} - -bool EventHub::hasLed(int32_t deviceId, int32_t led) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && led >= 0 && led <= LED_MAX) { - if (test_bit(led, device->ledBitmask)) { - return true; - } - } - return false; -} - -void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && led >= 0 && led <= LED_MAX) { - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_LED; - ev.code = led; - ev.value = on ? 1 : 0; - - ssize_t nWrite; - do { - nWrite = write(device->fd, &ev, sizeof(struct input_event)); - } while (nWrite == -1 && errno == EINTR); - } -} - -void EventHub::getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const { - outVirtualKeys.clear(); - - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->virtualKeyMap) { - outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); - } -} - -sp<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - return device->getKeyCharacterMap(); - } - return NULL; -} - -bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, - const sp<KeyCharacterMap>& map) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - if (map != device->overlayKeyMap) { - device->overlayKeyMap = map; - device->combinedKeyMap = KeyCharacterMap::combine( - device->keyMap.keyCharacterMap, map); - return true; - } - } - return false; -} - -void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { - ff_effect effect; - memset(&effect, 0, sizeof(effect)); - effect.type = FF_RUMBLE; - effect.id = device->ffEffectId; - effect.u.rumble.strong_magnitude = 0xc000; - effect.u.rumble.weak_magnitude = 0xc000; - effect.replay.length = (duration + 999999LL) / 1000000LL; - effect.replay.delay = 0; - if (ioctl(device->fd, EVIOCSFF, &effect)) { - ALOGW("Could not upload force feedback effect to device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - device->ffEffectId = effect.id; - - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_FF; - ev.code = device->ffEffectId; - ev.value = 1; - if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { - ALOGW("Could not start force feedback effect on device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - device->ffEffectPlaying = true; - } -} - -void EventHub::cancelVibrate(int32_t deviceId) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { - if (device->ffEffectPlaying) { - device->ffEffectPlaying = false; - - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_FF; - ev.code = device->ffEffectId; - ev.value = 0; - if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { - ALOGW("Could not stop force feedback effect on device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - } - } -} - -EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { - if (deviceId == BUILT_IN_KEYBOARD_ID) { - deviceId = mBuiltInKeyboardId; - } - ssize_t index = mDevices.indexOfKey(deviceId); - return index >= 0 ? mDevices.valueAt(index) : NULL; -} - -EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const { - for (size_t i = 0; i < mDevices.size(); i++) { - Device* device = mDevices.valueAt(i); - if (device->path == devicePath) { - return device; - } - } - return NULL; -} - -size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { - ALOG_ASSERT(bufferSize >= 1); - - AutoMutex _l(mLock); - - struct input_event readBuffer[bufferSize]; - - RawEvent* event = buffer; - size_t capacity = bufferSize; - bool awoken = false; - for (;;) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - // Reopen input devices if needed. - if (mNeedToReopenDevices) { - mNeedToReopenDevices = false; - - ALOGI("Reopening all input devices due to a configuration change."); - - closeAllDevicesLocked(); - mNeedToScanDevices = true; - break; // return to the caller before we actually rescan - } - - // Report any devices that had last been added/removed. - while (mClosingDevices) { - Device* device = mClosingDevices; - ALOGV("Reporting device closed: id=%d, name=%s\n", - device->id, device->path.string()); - mClosingDevices = device->next; - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; - event->type = DEVICE_REMOVED; - event += 1; - delete device; - mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { - break; - } - } - - if (mNeedToScanDevices) { - mNeedToScanDevices = false; - scanDevicesLocked(); - mNeedToSendFinishedDeviceScan = true; - } - - while (mOpeningDevices != NULL) { - Device* device = mOpeningDevices; - ALOGV("Reporting device opened: id=%d, name=%s\n", - device->id, device->path.string()); - mOpeningDevices = device->next; - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - event->type = DEVICE_ADDED; - event += 1; - mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { - break; - } - } - - if (mNeedToSendFinishedDeviceScan) { - mNeedToSendFinishedDeviceScan = false; - event->when = now; - event->type = FINISHED_DEVICE_SCAN; - event += 1; - if (--capacity == 0) { - break; - } - } - - // Grab the next input event. - bool deviceChanged = false; - while (mPendingEventIndex < mPendingEventCount) { - const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; - if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { - if (eventItem.events & EPOLLIN) { - mPendingINotify = true; - } else { - ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events); - } - continue; - } - - if (eventItem.data.u32 == EPOLL_ID_WAKE) { - if (eventItem.events & EPOLLIN) { - ALOGV("awoken after wake()"); - awoken = true; - char buffer[16]; - ssize_t nRead; - do { - nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); - } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); - } else { - ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", - eventItem.events); - } - continue; - } - - ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); - if (deviceIndex < 0) { - ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.", - eventItem.events, eventItem.data.u32); - continue; - } - - Device* device = mDevices.valueAt(deviceIndex); - if (eventItem.events & EPOLLIN) { - int32_t readSize = read(device->fd, readBuffer, - sizeof(struct input_event) * capacity); - if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { - // Device was removed before INotify noticed. - ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d " - "capacity: %d errno: %d)\n", - device->fd, readSize, bufferSize, capacity, errno); - deviceChanged = true; - closeDeviceLocked(device); - } else if (readSize < 0) { - if (errno != EAGAIN && errno != EINTR) { - ALOGW("could not get event (errno=%d)", errno); - } - } else if ((readSize % sizeof(struct input_event)) != 0) { - ALOGE("could not get event (wrong size: %d)", readSize); - } else { - int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - - size_t count = size_t(readSize) / sizeof(struct input_event); - for (size_t i = 0; i < count; i++) { - struct input_event& iev = readBuffer[i]; - ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d", - device->path.string(), - (int) iev.time.tv_sec, (int) iev.time.tv_usec, - iev.type, iev.code, iev.value); - - // Some input devices may have a better concept of the time - // when an input event was actually generated than the kernel - // which simply timestamps all events on entry to evdev. - // This is a custom Android extension of the input protocol - // mainly intended for use with uinput based device drivers. - if (iev.type == EV_MSC) { - if (iev.code == MSC_ANDROID_TIME_SEC) { - device->timestampOverrideSec = iev.value; - continue; - } else if (iev.code == MSC_ANDROID_TIME_USEC) { - device->timestampOverrideUsec = iev.value; - continue; - } - } - if (device->timestampOverrideSec || device->timestampOverrideUsec) { - iev.time.tv_sec = device->timestampOverrideSec; - iev.time.tv_usec = device->timestampOverrideUsec; - if (iev.type == EV_SYN && iev.code == SYN_REPORT) { - device->timestampOverrideSec = 0; - device->timestampOverrideUsec = 0; - } - ALOGV("applied override time %d.%06d", - int(iev.time.tv_sec), int(iev.time.tv_usec)); - } - -#ifdef HAVE_POSIX_CLOCKS - // Use the time specified in the event instead of the current time - // so that downstream code can get more accurate estimates of - // event dispatch latency from the time the event is enqueued onto - // the evdev client buffer. - // - // The event's timestamp fortuitously uses the same monotonic clock - // time base as the rest of Android. The kernel event device driver - // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts(). - // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere - // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a - // system call that also queries ktime_get_ts(). - event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL - + nsecs_t(iev.time.tv_usec) * 1000LL; - ALOGV("event time %lld, now %lld", event->when, now); - - // Bug 7291243: Add a guard in case the kernel generates timestamps - // that appear to be far into the future because they were generated - // using the wrong clock source. - // - // This can happen because when the input device is initially opened - // it has a default clock source of CLOCK_REALTIME. Any input events - // enqueued right after the device is opened will have timestamps - // generated using CLOCK_REALTIME. We later set the clock source - // to CLOCK_MONOTONIC but it is already too late. - // - // Invalid input event timestamps can result in ANRs, crashes and - // and other issues that are hard to track down. We must not let them - // propagate through the system. - // - // Log a warning so that we notice the problem and recover gracefully. - if (event->when >= now + 10 * 1000000000LL) { - // Double-check. Time may have moved on. - nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC); - if (event->when > time) { - ALOGW("An input event from %s has a timestamp that appears to " - "have been generated using the wrong clock source " - "(expected CLOCK_MONOTONIC): " - "event time %lld, current time %lld, call time %lld. " - "Using current time instead.", - device->path.string(), event->when, time, now); - event->when = time; - } else { - ALOGV("Event time is ok but failed the fast path and required " - "an extra call to systemTime: " - "event time %lld, current time %lld, call time %lld.", - event->when, time, now); - } - } -#else - event->when = now; -#endif - event->deviceId = deviceId; - event->type = iev.type; - event->code = iev.code; - event->value = iev.value; - event += 1; - capacity -= 1; - } - if (capacity == 0) { - // The result buffer is full. Reset the pending event index - // so we will try to read the device again on the next iteration. - mPendingEventIndex -= 1; - break; - } - } - } else if (eventItem.events & EPOLLHUP) { - ALOGI("Removing device %s due to epoll hang-up event.", - device->identifier.name.string()); - deviceChanged = true; - closeDeviceLocked(device); - } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", - eventItem.events, device->identifier.name.string()); - } - } - - // readNotify() will modify the list of devices so this must be done after - // processing all other events to ensure that we read all remaining events - // before closing the devices. - if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { - mPendingINotify = false; - readNotifyLocked(); - deviceChanged = true; - } - - // Report added or removed devices immediately. - if (deviceChanged) { - continue; - } - - // Return now if we have collected any events or if we were explicitly awoken. - if (event != buffer || awoken) { - break; - } - - // Poll for events. Mind the wake lock dance! - // We hold a wake lock at all times except during epoll_wait(). This works due to some - // subtle choreography. When a device driver has pending (unread) events, it acquires - // a kernel wake lock. However, once the last pending event has been read, the device - // driver will release the kernel wake lock. To prevent the system from going to sleep - // when this happens, the EventHub holds onto its own user wake lock while the client - // is processing events. Thus the system can only sleep if there are no events - // pending or currently being processed. - // - // The timeout is advisory only. If the device is asleep, it will not wake just to - // service the timeout. - mPendingEventIndex = 0; - - mLock.unlock(); // release lock before poll, must be before release_wake_lock - release_wake_lock(WAKE_LOCK_ID); - - int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); - - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock - - if (pollResult == 0) { - // Timed out. - mPendingEventCount = 0; - break; - } - - if (pollResult < 0) { - // An error occurred. - mPendingEventCount = 0; - - // Sleep after errors to avoid locking up the system. - // Hopefully the error is transient. - if (errno != EINTR) { - ALOGW("poll failed (errno=%d)\n", errno); - usleep(100000); - } - } else { - // Some events occurred. - mPendingEventCount = size_t(pollResult); - } - } - - // All done, return the number of events we read. - return event - buffer; -} - -void EventHub::wake() { - ALOGV("wake() called"); - - ssize_t nWrite; - do { - nWrite = write(mWakeWritePipeFd, "W", 1); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite != 1 && errno != EAGAIN) { - ALOGW("Could not write wake signal, errno=%d", errno); - } -} - -void EventHub::scanDevicesLocked() { - status_t res = scanDirLocked(DEVICE_PATH); - if(res < 0) { - ALOGE("scan dir failed for %s\n", DEVICE_PATH); - } - if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) { - createVirtualKeyboardLocked(); - } -} - -// ---------------------------------------------------------------------------- - -static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { - const uint8_t* end = array + endIndex; - array += startIndex; - while (array != end) { - if (*(array++) != 0) { - return true; - } - } - return false; -} - -static const int32_t GAMEPAD_KEYCODES[] = { - AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, - AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, - AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, - AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, - AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, - AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, - AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4, - AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8, - AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12, - AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16, -}; - -status_t EventHub::openDeviceLocked(const char *devicePath) { - char buffer[80]; - - ALOGV("Opening device: %s", devicePath); - - int fd = open(devicePath, O_RDWR | O_CLOEXEC); - if(fd < 0) { - ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); - return -1; - } - - InputDeviceIdentifier identifier; - - // Get device name. - if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.name.setTo(buffer); - } - - // Check to see if the device is on our excluded list - for (size_t i = 0; i < mExcludedDevices.size(); i++) { - const String8& item = mExcludedDevices.itemAt(i); - if (identifier.name == item) { - ALOGI("ignoring event id %s driver %s\n", devicePath, item.string()); - close(fd); - return -1; - } - } - - // Get device driver version. - int driverVersion; - if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { - ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - - // Get device identifier. - struct input_id inputId; - if(ioctl(fd, EVIOCGID, &inputId)) { - ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - identifier.bus = inputId.bustype; - identifier.product = inputId.product; - identifier.vendor = inputId.vendor; - identifier.version = inputId.version; - - // Get device physical location. - if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.location.setTo(buffer); - } - - // Get device unique id. - if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.uniqueId.setTo(buffer); - } - - // Fill in the descriptor. - setDescriptor(identifier); - - // Make file descriptor non-blocking for use with poll(). - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - ALOGE("Error %d making device file descriptor non-blocking.", errno); - close(fd); - return -1; - } - - // Allocate device. (The device object takes ownership of the fd at this point.) - int32_t deviceId = mNextDeviceId++; - Device* device = new Device(fd, deviceId, String8(devicePath), identifier); - - ALOGV("add device %d: %s\n", deviceId, devicePath); - ALOGV(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - identifier.bus, identifier.vendor, identifier.product, identifier.version); - ALOGV(" name: \"%s\"\n", identifier.name.string()); - ALOGV(" location: \"%s\"\n", identifier.location.string()); - ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string()); - ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string()); - ALOGV(" driver: v%d.%d.%d\n", - driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); - - // Load the configuration file for the device. - loadConfigurationLocked(device); - - // Figure out the kinds of events the device reports. - ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); - ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); - ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); - ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); - ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); - ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); - - // See if this is a keyboard. Ignore everything in the button range except for - // joystick and gamepad buttons which are handled like keyboards for the most part. - bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1)); - bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), - sizeof_bit_array(BTN_MOUSE)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), - sizeof_bit_array(BTN_DIGI)); - if (haveKeyboardKeys || haveGamepadButtons) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - - // See if this is a cursor device such as a trackball or mouse. - if (test_bit(BTN_MOUSE, device->keyBitmask) - && test_bit(REL_X, device->relBitmask) - && test_bit(REL_Y, device->relBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_CURSOR; - } - - // See if this is a touch pad. - // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, device->absBitmask) - && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { - // Some joysticks such as the PS3 controller report axes that conflict - // with the ABS_MT range. Try to confirm that the device really is - // a touch screen. - if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; - } - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, device->keyBitmask) - && test_bit(ABS_X, device->absBitmask) - && test_bit(ABS_Y, device->absBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH; - } - - // See if this device is a joystick. - // Assumes that joysticks always have gamepad buttons in order to distinguish them - // from other devices such as accelerometers that also have absolute axes. - if (haveGamepadButtons) { - uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; - for (int i = 0; i <= ABS_MAX; i++) { - if (test_bit(i, device->absBitmask) - && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { - device->classes = assumedClasses; - break; - } - } - } - - // Check whether this device has switches. - for (int i = 0; i <= SW_MAX; i++) { - if (test_bit(i, device->swBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_SWITCH; - break; - } - } - - // Check whether this device supports the vibrator. - if (test_bit(FF_RUMBLE, device->ffBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; - } - - // Configure virtual keys. - if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { - // Load the virtual keys for the touch screen, if any. - // We do this now so that we can make sure to load the keymap if necessary. - status_t status = loadVirtualKeyMapLocked(device); - if (!status) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - } - - // Load the key map. - // We need to do this for joysticks too because the key layout may specify axes. - status_t keyMapStatus = NAME_NOT_FOUND; - if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { - // Load the keymap for the device. - keyMapStatus = loadKeyMapLocked(device); - } - - // Configure the keyboard, gamepad or virtual keyboard. - if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { - // Register the keyboard as a built-in keyboard if it is eligible. - if (!keyMapStatus - && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD - && isEligibleBuiltInKeyboard(device->identifier, - device->configuration, &device->keyMap)) { - mBuiltInKeyboardId = device->id; - } - - // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (hasKeycodeLocked(device, AKEYCODE_Q)) { - device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; - } - - // See if this device has a DPAD. - if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && - hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && - hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { - device->classes |= INPUT_DEVICE_CLASS_DPAD; - } - - // See if this device has a gamepad. - for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { - if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { - device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; - break; - } - } - - // Disable kernel key repeat since we handle it ourselves - unsigned int repeatRate[] = {0,0}; - if (ioctl(fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); - } - } - - // If the device isn't recognized as something we handle, don't monitor it. - if (device->classes == 0) { - ALOGV("Dropping device: id=%d, path='%s', name='%s'", - deviceId, devicePath, device->identifier.name.string()); - delete device; - return -1; - } - - // Determine whether the device is external or internal. - if (isExternalDeviceLocked(device)) { - device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; - } - - // Register with epoll. - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - eventItem.data.u32 = deviceId; - if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { - ALOGE("Could not add device fd to epoll instance. errno=%d", errno); - delete device; - return -1; - } - - // Enable wake-lock behavior on kernels that support it. - // TODO: Only need this for devices that can really wake the system. - bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1); - - // Tell the kernel that we want to use the monotonic clock for reporting timestamps - // associated with input events. This is important because the input system - // uses the timestamps extensively and assumes they were recorded using the monotonic - // clock. - // - // In older kernel, before Linux 3.4, there was no way to tell the kernel which - // clock to use to input event timestamps. The standard kernel behavior was to - // record a real time timestamp, which isn't what we want. Android kernels therefore - // contained a patch to the evdev_event() function in drivers/input/evdev.c to - // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic - // clock to be used instead of the real time clock. - // - // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. - // Therefore, we no longer require the Android-specific kernel patch described above - // as long as we make sure to set select the monotonic clock. We do that here. - int clockId = CLOCK_MONOTONIC; - bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); - - ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " - "usingSuspendBlockIoctl=%s, usingClockIoctl=%s", - deviceId, fd, devicePath, device->identifier.name.string(), - device->classes, - device->configurationFile.string(), - device->keyMap.keyLayoutFile.string(), - device->keyMap.keyCharacterMapFile.string(), - toString(mBuiltInKeyboardId == deviceId), - toString(usingSuspendBlockIoctl), toString(usingClockIoctl)); - - addDeviceLocked(device); - return 0; -} - -void EventHub::createVirtualKeyboardLocked() { - InputDeviceIdentifier identifier; - identifier.name = "Virtual"; - identifier.uniqueId = "<virtual>"; - setDescriptor(identifier); - - Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8("<virtual>"), identifier); - device->classes = INPUT_DEVICE_CLASS_KEYBOARD - | INPUT_DEVICE_CLASS_ALPHAKEY - | INPUT_DEVICE_CLASS_DPAD - | INPUT_DEVICE_CLASS_VIRTUAL; - loadKeyMapLocked(device); - addDeviceLocked(device); -} - -void EventHub::addDeviceLocked(Device* device) { - mDevices.add(device->id, device); - device->next = mOpeningDevices; - mOpeningDevices = device; -} - -void EventHub::loadConfigurationLocked(Device* device) { - device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( - device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); - if (device->configurationFile.isEmpty()) { - ALOGD("No input device configuration file found for device '%s'.", - device->identifier.name.string()); - } else { - status_t status = PropertyMap::load(device->configurationFile, - &device->configuration); - if (status) { - ALOGE("Error loading input device configuration file for device '%s'. " - "Using default configuration.", - device->identifier.name.string()); - } - } -} - -status_t EventHub::loadVirtualKeyMapLocked(Device* device) { - // The virtual key map is supplied by the kernel as a system board property file. - String8 path; - path.append("/sys/board_properties/virtualkeys."); - path.append(device->identifier.name); - if (access(path.string(), R_OK)) { - return NAME_NOT_FOUND; - } - return VirtualKeyMap::load(path, &device->virtualKeyMap); -} - -status_t EventHub::loadKeyMapLocked(Device* device) { - return device->keyMap.load(device->identifier, device->configuration); -} - -bool EventHub::isExternalDeviceLocked(Device* device) { - if (device->configuration) { - bool value; - if (device->configuration->tryGetProperty(String8("device.internal"), value)) { - return !value; - } - } - return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; -} - -bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { - if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { - return false; - } - - Vector<int32_t> scanCodes; - device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); - const size_t N = scanCodes.size(); - for (size_t i=0; i<N && i<=KEY_MAX; i++) { - int32_t sc = scanCodes.itemAt(i); - if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { - return true; - } - } - - return false; -} - -status_t EventHub::closeDeviceByPathLocked(const char *devicePath) { - Device* device = getDeviceByPathLocked(devicePath); - if (device) { - closeDeviceLocked(device); - return 0; - } - ALOGV("Remove device: %s not found, device may already have been removed.", devicePath); - return -1; -} - -void EventHub::closeAllDevicesLocked() { - while (mDevices.size() > 0) { - closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1)); - } -} - -void EventHub::closeDeviceLocked(Device* device) { - ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", - device->path.string(), device->identifier.name.string(), device->id, - device->fd, device->classes); - - if (device->id == mBuiltInKeyboardId) { - ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.string(), mBuiltInKeyboardId); - mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; - } - - if (!device->isVirtual()) { - if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { - ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); - } - } - - mDevices.removeItem(device->id); - device->close(); - - // Unlink for opening devices list if it is present. - Device* pred = NULL; - bool found = false; - for (Device* entry = mOpeningDevices; entry != NULL; ) { - if (entry == device) { - found = true; - break; - } - pred = entry; - entry = entry->next; - } - if (found) { - // Unlink the device from the opening devices list then delete it. - // We don't need to tell the client that the device was closed because - // it does not even know it was opened in the first place. - ALOGI("Device %s was immediately closed after opening.", device->path.string()); - if (pred) { - pred->next = device->next; - } else { - mOpeningDevices = device->next; - } - delete device; - } else { - // Link into closing devices list. - // The device will be deleted later after we have informed the client. - device->next = mClosingDevices; - mClosingDevices = device; - } -} - -status_t EventHub::readNotifyLocked() { - int res; - char devname[PATH_MAX]; - char *filename; - char event_buf[512]; - int event_size; - int event_pos = 0; - struct inotify_event *event; - - ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); - res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if(res < (int)sizeof(*event)) { - if(errno == EINTR) - return 0; - ALOGW("could not get event, %s\n", strerror(errno)); - return -1; - } - //printf("got %d bytes of event information\n", res); - - strcpy(devname, DEVICE_PATH); - filename = devname + strlen(devname); - *filename++ = '/'; - - while(res >= (int)sizeof(*event)) { - event = (struct inotify_event *)(event_buf + event_pos); - //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); - if(event->len) { - strcpy(filename, event->name); - if(event->mask & IN_CREATE) { - openDeviceLocked(devname); - } else { - ALOGI("Removing device '%s' due to inotify event\n", devname); - closeDeviceByPathLocked(devname); - } - } - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } - return 0; -} - -status_t EventHub::scanDirLocked(const char *dirname) -{ - char devname[PATH_MAX]; - char *filename; - DIR *dir; - struct dirent *de; - dir = opendir(dirname); - if(dir == NULL) - return -1; - strcpy(devname, dirname); - filename = devname + strlen(devname); - *filename++ = '/'; - while((de = readdir(dir))) { - if(de->d_name[0] == '.' && - (de->d_name[1] == '\0' || - (de->d_name[1] == '.' && de->d_name[2] == '\0'))) - continue; - strcpy(filename, de->d_name); - openDeviceLocked(devname); - } - closedir(dir); - return 0; -} - -void EventHub::requestReopenDevices() { - ALOGV("requestReopenDevices() called"); - - AutoMutex _l(mLock); - mNeedToReopenDevices = true; -} - -void EventHub::dump(String8& dump) { - dump.append("Event Hub State:\n"); - - { // acquire lock - AutoMutex _l(mLock); - - dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); - - dump.append(INDENT "Devices:\n"); - - for (size_t i = 0; i < mDevices.size(); i++) { - const Device* device = mDevices.valueAt(i); - if (mBuiltInKeyboardId == device->id) { - dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", - device->id, device->identifier.name.string()); - } else { - dump.appendFormat(INDENT2 "%d: %s\n", device->id, - device->identifier.name.string()); - } - dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); - dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); - dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); - dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); - dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " - "product=0x%04x, version=0x%04x\n", - device->identifier.bus, device->identifier.vendor, - device->identifier.product, device->identifier.version); - dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", - device->keyMap.keyLayoutFile.string()); - dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMap.keyCharacterMapFile.string()); - dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", - device->configurationFile.string()); - dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", - toString(device->overlayKeyMap != NULL)); - } - } // release lock -} - -void EventHub::monitor() { - // Acquire and release the lock to ensure that the event hub has not deadlocked. - mLock.lock(); - mLock.unlock(); -} - - -}; // namespace android diff --git a/widget/gonk/libui/EventHub.h b/widget/gonk/libui/EventHub.h deleted file mode 100644 index e4e658b21..000000000 --- a/widget/gonk/libui/EventHub.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * 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. - */ - -// -#ifndef _RUNTIME_EVENT_HUB_H -#define _RUNTIME_EVENT_HUB_H - -#include "Input.h" -#include "InputDevice.h" -#include "Keyboard.h" -#include "KeyLayoutMap.h" -#include "KeyCharacterMap.h" -#include "VirtualKeyMap.h" -#include <utils/String8.h> -#include <utils/threads.h> -#include "cutils_log.h" -#include <utils/threads.h> -#include <utils/List.h> -#include <utils/Errors.h> -#include <utils/PropertyMap.h> -#include <utils/Vector.h> -#include <utils/KeyedVector.h> - -#include "linux_input.h" -#include <sys/epoll.h> - -/* Convenience constants. */ - -#define BTN_FIRST 0x100 // first button code -#define BTN_LAST 0x15f // last button code - -/* - * These constants are used privately in Android to pass raw timestamps - * through evdev from uinput device drivers because there is currently no - * other way to transfer this information. The evdev driver automatically - * timestamps all input events with the time they were posted and clobbers - * whatever information was passed in. - * - * For the purposes of this hack, the timestamp is specified in the - * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying - * seconds and microseconds. - */ -#define MSC_ANDROID_TIME_SEC 0x6 -#define MSC_ANDROID_TIME_USEC 0x7 - -namespace android { - -enum { - // Device id of a special "virtual" keyboard that is always present. - VIRTUAL_KEYBOARD_ID = -1, - // Device id of the "built-in" keyboard if there is one. - BUILT_IN_KEYBOARD_ID = 0, -}; - -/* - * A raw event as retrieved from the EventHub. - */ -struct RawEvent { - nsecs_t when; - int32_t deviceId; - int32_t type; - int32_t code; - int32_t value; -}; - -/* Describes an absolute axis. */ -struct RawAbsoluteAxisInfo { - bool valid; // true if the information is valid, false otherwise - - int32_t minValue; // minimum value - int32_t maxValue; // maximum value - int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 - int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise - int32_t resolution; // resolution in units per mm or radians per mm - - inline void clear() { - valid = false; - minValue = 0; - maxValue = 0; - flat = 0; - fuzz = 0; - resolution = 0; - } -}; - -/* - * Input device classes. - */ -enum { - /* The input device is a keyboard or has buttons. */ - INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, - - /* The input device is an alpha-numeric keyboard (not just a dial pad). */ - INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, - - /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ - INPUT_DEVICE_CLASS_TOUCH = 0x00000004, - - /* The input device is a cursor device such as a trackball or mouse. */ - INPUT_DEVICE_CLASS_CURSOR = 0x00000008, - - /* The input device is a multi-touch touchscreen. */ - INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, - - /* The input device is a directional pad (implies keyboard, has DPAD keys). */ - INPUT_DEVICE_CLASS_DPAD = 0x00000020, - - /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ - INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, - - /* The input device has switches. */ - INPUT_DEVICE_CLASS_SWITCH = 0x00000080, - - /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ - INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, - - /* The input device has a vibrator (supports FF_RUMBLE). */ - INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, - - /* The input device is virtual (not a real device, not part of UI configuration). */ - INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, - - /* The input device is external (not built-in). */ - INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, -}; - -/* - * Gets the class that owns an axis, in cases where multiple classes might claim - * the same axis for different purposes. - */ -extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); - -/* - * Grand Central Station for events. - * - * The event hub aggregates input events received across all known input - * devices on the system, including devices that may be emulated by the simulator - * environment. In addition, the event hub generates fake input events to indicate - * when devices are added or removed. - * - * The event hub provides a stream of input events (via the getEvent function). - * It also supports querying the current actual state of input devices such as identifying - * which keys are currently down. Finally, the event hub keeps track of the capabilities of - * individual input devices, such as their class and the set of key codes that they support. - */ -class EventHubInterface : public virtual RefBase { -protected: - EventHubInterface() { } - virtual ~EventHubInterface() { } - -public: - // Synthetic raw event type codes produced when devices are added or removed. - enum { - // Sent when a device is added. - DEVICE_ADDED = 0x10000000, - // Sent when a device is removed. - DEVICE_REMOVED = 0x20000000, - // Sent when all added/removed devices from the most recent scan have been reported. - // This event is always sent at least once. - FINISHED_DEVICE_SCAN = 0x30000000, - - FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, - }; - - virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const = 0; - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; - - virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const = 0; - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const = 0; - - // Sets devices that are excluded from opening. - // This can be used to ignore input devices for sensors. - virtual void setExcludedDevices(const Vector<String8>& devices) = 0; - - /* - * Wait for events to become available and returns them. - * After returning, the EventHub holds onto a wake lock until the next call to getEvent. - * This ensures that the device will not go to sleep while the event is being processed. - * If the device needs to remain awake longer than that, then the caller is responsible - * for taking care of it (say, by poking the power manager user activity timer). - * - * The timeout is advisory only. If the device is asleep, it will not wake just to - * service the timeout. - * - * Returns the number of events obtained, or 0 if the timeout expired. - */ - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; - - /* - * Query current input state. - */ - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const = 0; - - /* - * Examine key input devices for specific framework keycode support - */ - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const = 0; - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; - virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; - virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const = 0; - - virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const = 0; - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map) = 0; - - /* Control the vibrator. */ - virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; - virtual void cancelVibrate(int32_t deviceId) = 0; - - /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ - virtual void requestReopenDevices() = 0; - - /* Wakes up getEvents() if it is blocked on a read. */ - virtual void wake() = 0; - - /* Dump EventHub state to a string. */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; -}; - -class EventHub : public EventHubInterface -{ -public: - EventHub(); - - virtual uint32_t getDeviceClasses(int32_t deviceId) const; - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const; - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const; - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; - - virtual bool hasInputProperty(int32_t deviceId, int property) const; - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const; - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const; - - virtual void setExcludedDevices(const Vector<String8>& devices); - - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; - - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const; - - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const; - virtual bool hasLed(int32_t deviceId, int32_t led) const; - virtual void setLedState(int32_t deviceId, int32_t led, bool on); - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector<VirtualKeyDefinition>& outVirtualKeys) const; - - virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const; - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map); - - virtual void vibrate(int32_t deviceId, nsecs_t duration); - virtual void cancelVibrate(int32_t deviceId); - - virtual void requestReopenDevices(); - - virtual void wake(); - - virtual void dump(String8& dump); - virtual void monitor(); - -protected: - virtual ~EventHub(); - -private: - struct Device { - Device* next; - - int fd; // may be -1 if device is virtual - const int32_t id; - const String8 path; - const InputDeviceIdentifier identifier; - - uint32_t classes; - - uint8_t keyBitmask[(KEY_MAX + 1) / 8]; - uint8_t absBitmask[(ABS_MAX + 1) / 8]; - uint8_t relBitmask[(REL_MAX + 1) / 8]; - uint8_t swBitmask[(SW_MAX + 1) / 8]; - uint8_t ledBitmask[(LED_MAX + 1) / 8]; - uint8_t ffBitmask[(FF_MAX + 1) / 8]; - uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; - - String8 configurationFile; - PropertyMap* configuration; - VirtualKeyMap* virtualKeyMap; - KeyMap keyMap; - - sp<KeyCharacterMap> overlayKeyMap; - sp<KeyCharacterMap> combinedKeyMap; - - bool ffEffectPlaying; - int16_t ffEffectId; // initially -1 - - int32_t timestampOverrideSec; - int32_t timestampOverrideUsec; - - Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); - ~Device(); - - void close(); - - inline bool isVirtual() const { return fd < 0; } - - const sp<KeyCharacterMap>& getKeyCharacterMap() const { - if (combinedKeyMap != NULL) { - return combinedKeyMap; - } - return keyMap.keyCharacterMap; - } - }; - - status_t openDeviceLocked(const char *devicePath); - void createVirtualKeyboardLocked(); - void addDeviceLocked(Device* device); - - status_t closeDeviceByPathLocked(const char *devicePath); - void closeDeviceLocked(Device* device); - void closeAllDevicesLocked(); - - status_t scanDirLocked(const char *dirname); - void scanDevicesLocked(); - status_t readNotifyLocked(); - - Device* getDeviceLocked(int32_t deviceId) const; - Device* getDeviceByPathLocked(const char* devicePath) const; - - bool hasKeycodeLocked(Device* device, int keycode) const; - - void loadConfigurationLocked(Device* device); - status_t loadVirtualKeyMapLocked(Device* device); - status_t loadKeyMapLocked(Device* device); - - bool isExternalDeviceLocked(Device* device); - - // Protect all internal state. - mutable Mutex mLock; - - // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none. - // EventHub remaps the built-in keyboard to id 0 externally as required by the API. - enum { - // Must not conflict with any other assigned device ids, including - // the virtual keyboard id (-1). - NO_BUILT_IN_KEYBOARD = -2, - }; - int32_t mBuiltInKeyboardId; - - int32_t mNextDeviceId; - - KeyedVector<int32_t, Device*> mDevices; - - Device *mOpeningDevices; - Device *mClosingDevices; - - bool mNeedToSendFinishedDeviceScan; - bool mNeedToReopenDevices; - bool mNeedToScanDevices; - Vector<String8> mExcludedDevices; - - int mEpollFd; - int mINotifyFd; - int mWakeReadPipeFd; - int mWakeWritePipeFd; - - // Ids used for epoll notifications not associated with devices. - static const uint32_t EPOLL_ID_INOTIFY = 0x80000001; - static const uint32_t EPOLL_ID_WAKE = 0x80000002; - - // Epoll FD list size hint. - static const int EPOLL_SIZE_HINT = 8; - - // Maximum number of signalled FDs to handle at a time. - static const int EPOLL_MAX_EVENTS = 16; - - // The array of pending epoll events and the index of the next event to be handled. - struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; - size_t mPendingEventCount; - size_t mPendingEventIndex; - bool mPendingINotify; -}; - -}; // namespace android - -#endif // _RUNTIME_EVENT_HUB_H diff --git a/widget/gonk/libui/Input.cpp b/widget/gonk/libui/Input.cpp deleted file mode 100644 index 2208191e6..000000000 --- a/widget/gonk/libui/Input.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Input" -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -#include <math.h> -#include <limits.h> - -#include "Input.h" - -#ifdef HAVE_ANDROID_OS -#include <binder/Parcel.h> - -#include "SkPoint.h" -#include "SkMatrix.h" -#include "SkScalar.h" -#endif - -namespace android { - -// --- InputEvent --- - -void InputEvent::initialize(int32_t deviceId, int32_t source) { - mDeviceId = deviceId; - mSource = source; -} - -void InputEvent::initialize(const InputEvent& from) { - mDeviceId = from.mDeviceId; - mSource = from.mSource; -} - -// --- KeyEvent --- - -bool KeyEvent::hasDefaultAction(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_HOME: - case AKEYCODE_BACK: - case AKEYCODE_CALL: - case AKEYCODE_ENDCALL: - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_VOLUME_MUTE: - case AKEYCODE_POWER: - case AKEYCODE_CAMERA: - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MENU: - case AKEYCODE_NOTIFICATION: - case AKEYCODE_FOCUS: - case AKEYCODE_SEARCH: - case AKEYCODE_MEDIA_PLAY: - case AKEYCODE_MEDIA_PAUSE: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_RECORD: - case AKEYCODE_MEDIA_FAST_FORWARD: - case AKEYCODE_MUTE: - case AKEYCODE_BRIGHTNESS_DOWN: - case AKEYCODE_BRIGHTNESS_UP: - return true; - } - - return false; -} - -bool KeyEvent::hasDefaultAction() const { - return hasDefaultAction(getKeyCode()); -} - -bool KeyEvent::isSystemKey(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_MENU: - case AKEYCODE_SOFT_RIGHT: - case AKEYCODE_HOME: - case AKEYCODE_BACK: - case AKEYCODE_CALL: - case AKEYCODE_ENDCALL: - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_VOLUME_MUTE: - case AKEYCODE_MUTE: - case AKEYCODE_POWER: - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MEDIA_PLAY: - case AKEYCODE_MEDIA_PAUSE: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_RECORD: - case AKEYCODE_MEDIA_FAST_FORWARD: - case AKEYCODE_CAMERA: - case AKEYCODE_FOCUS: - case AKEYCODE_SEARCH: - case AKEYCODE_BRIGHTNESS_DOWN: - case AKEYCODE_BRIGHTNESS_UP: - return true; - } - - return false; -} - -bool KeyEvent::isSystemKey() const { - return isSystemKey(getKeyCode()); -} - -void KeyEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime) { - InputEvent::initialize(deviceId, source); - mAction = action; - mFlags = flags; - mKeyCode = keyCode; - mScanCode = scanCode; - mMetaState = metaState; - mRepeatCount = repeatCount; - mDownTime = downTime; - mEventTime = eventTime; -} - -void KeyEvent::initialize(const KeyEvent& from) { - InputEvent::initialize(from); - mAction = from.mAction; - mFlags = from.mFlags; - mKeyCode = from.mKeyCode; - mScanCode = from.mScanCode; - mMetaState = from.mMetaState; - mRepeatCount = from.mRepeatCount; - mDownTime = from.mDownTime; - mEventTime = from.mEventTime; -} - - -// --- PointerCoords --- - -float PointerCoords::getAxisValue(int32_t axis) const { - if (axis < 0 || axis > 63) { - return 0; - } - - uint64_t axisBit = 1LL << axis; - if (!(bits & axisBit)) { - return 0; - } - uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); - return values[index]; -} - -status_t PointerCoords::setAxisValue(int32_t axis, float value) { - if (axis < 0 || axis > 63) { - return NAME_NOT_FOUND; - } - - uint64_t axisBit = 1LL << axis; - uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); - if (!(bits & axisBit)) { - if (value == 0) { - return OK; // axes with value 0 do not need to be stored - } - uint32_t count = __builtin_popcountll(bits); - if (count >= MAX_AXES) { - tooManyAxes(axis); - return NO_MEMORY; - } - bits |= axisBit; - for (uint32_t i = count; i > index; i--) { - values[i] = values[i - 1]; - } - } - values[index] = value; - return OK; -} - -static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) { - float value = c.getAxisValue(axis); - if (value != 0) { - c.setAxisValue(axis, value * scaleFactor); - } -} - -void PointerCoords::scale(float scaleFactor) { - // No need to scale pressure or size since they are normalized. - // No need to scale orientation since it is meaningless to do so. - scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); -} - -#ifdef HAVE_ANDROID_OS -status_t PointerCoords::readFromParcel(Parcel* parcel) { - bits = parcel->readInt64(); - - uint32_t count = __builtin_popcountll(bits); - if (count > MAX_AXES) { - return BAD_VALUE; - } - - for (uint32_t i = 0; i < count; i++) { - values[i] = parcel->readFloat(); - } - return OK; -} - -status_t PointerCoords::writeToParcel(Parcel* parcel) const { - parcel->writeInt64(bits); - - uint32_t count = __builtin_popcountll(bits); - for (uint32_t i = 0; i < count; i++) { - parcel->writeFloat(values[i]); - } - return OK; -} -#endif - -void PointerCoords::tooManyAxes(int axis) { - ALOGW("Could not set value for axis %d because the PointerCoords structure is full and " - "cannot contain more than %d axis values.", axis, int(MAX_AXES)); -} - -bool PointerCoords::operator==(const PointerCoords& other) const { - if (bits != other.bits) { - return false; - } - uint32_t count = __builtin_popcountll(bits); - for (uint32_t i = 0; i < count; i++) { - if (values[i] != other.values[i]) { - return false; - } - } - return true; -} - -void PointerCoords::copyFrom(const PointerCoords& other) { - bits = other.bits; - uint32_t count = __builtin_popcountll(bits); - for (uint32_t i = 0; i < count; i++) { - values[i] = other.values[i]; - } -} - - -// --- PointerProperties --- - -bool PointerProperties::operator==(const PointerProperties& other) const { - return id == other.id - && toolType == other.toolType; -} - -void PointerProperties::copyFrom(const PointerProperties& other) { - id = other.id; - toolType = other.toolType; -} - - -// --- MotionEvent --- - -void MotionEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { - InputEvent::initialize(deviceId, source); - mAction = action; - mFlags = flags; - mEdgeFlags = edgeFlags; - mMetaState = metaState; - mButtonState = buttonState; - mXOffset = xOffset; - mYOffset = yOffset; - mXPrecision = xPrecision; - mYPrecision = yPrecision; - mDownTime = downTime; - mPointerProperties.clear(); - mPointerProperties.appendArray(pointerProperties, pointerCount); - mSampleEventTimes.clear(); - mSamplePointerCoords.clear(); - addSample(eventTime, pointerCoords); -} - -void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { - InputEvent::initialize(other->mDeviceId, other->mSource); - mAction = other->mAction; - mFlags = other->mFlags; - mEdgeFlags = other->mEdgeFlags; - mMetaState = other->mMetaState; - mButtonState = other->mButtonState; - mXOffset = other->mXOffset; - mYOffset = other->mYOffset; - mXPrecision = other->mXPrecision; - mYPrecision = other->mYPrecision; - mDownTime = other->mDownTime; - mPointerProperties = other->mPointerProperties; - - if (keepHistory) { - mSampleEventTimes = other->mSampleEventTimes; - mSamplePointerCoords = other->mSamplePointerCoords; - } else { - mSampleEventTimes.clear(); - mSampleEventTimes.push(other->getEventTime()); - mSamplePointerCoords.clear(); - size_t pointerCount = other->getPointerCount(); - size_t historySize = other->getHistorySize(); - mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() - + (historySize * pointerCount), pointerCount); - } -} - -void MotionEvent::addSample( - int64_t eventTime, - const PointerCoords* pointerCoords) { - mSampleEventTimes.push(eventTime); - mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); -} - -const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { - return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; -} - -float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const { - return getRawPointerCoords(pointerIndex)->getAxisValue(axis); -} - -float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { - float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); - switch (axis) { - case AMOTION_EVENT_AXIS_X: - return value + mXOffset; - case AMOTION_EVENT_AXIS_Y: - return value + mYOffset; - } - return value; -} - -const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( - size_t pointerIndex, size_t historicalIndex) const { - return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; -} - -float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { - return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); -} - -float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { - float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); - switch (axis) { - case AMOTION_EVENT_AXIS_X: - return value + mXOffset; - case AMOTION_EVENT_AXIS_Y: - return value + mYOffset; - } - return value; -} - -ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { - size_t pointerCount = mPointerProperties.size(); - for (size_t i = 0; i < pointerCount; i++) { - if (mPointerProperties.itemAt(i).id == pointerId) { - return i; - } - } - return -1; -} - -void MotionEvent::offsetLocation(float xOffset, float yOffset) { - mXOffset += xOffset; - mYOffset += yOffset; -} - -void MotionEvent::scale(float scaleFactor) { - mXOffset *= scaleFactor; - mYOffset *= scaleFactor; - mXPrecision *= scaleFactor; - mYPrecision *= scaleFactor; - - size_t numSamples = mSamplePointerCoords.size(); - for (size_t i = 0; i < numSamples; i++) { - mSamplePointerCoords.editItemAt(i).scale(scaleFactor); - } -} - -#ifdef HAVE_ANDROID_OS -static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { - // Construct and transform a vector oriented at the specified clockwise angle from vertical. - // Coordinate system: down is increasing Y, right is increasing X. - SkPoint vector; - vector.fX = SkFloatToScalar(sinf(angleRadians)); - vector.fY = SkFloatToScalar(-cosf(angleRadians)); - matrix->mapVectors(& vector, 1); - - // Derive the transformed vector's clockwise angle from vertical. - float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY)); - if (result < - M_PI_2) { - result += M_PI; - } else if (result > M_PI_2) { - result -= M_PI; - } - return result; -} - -void MotionEvent::transform(const SkMatrix* matrix) { - float oldXOffset = mXOffset; - float oldYOffset = mYOffset; - - // The tricky part of this implementation is to preserve the value of - // rawX and rawY. So we apply the transformation to the first point - // then derive an appropriate new X/Y offset that will preserve rawX and rawY. - SkPoint point; - float rawX = getRawX(0); - float rawY = getRawY(0); - matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset), - & point); - float newX = SkScalarToFloat(point.fX); - float newY = SkScalarToFloat(point.fY); - float newXOffset = newX - rawX; - float newYOffset = newY - rawY; - - mXOffset = newXOffset; - mYOffset = newYOffset; - - // Apply the transformation to all samples. - size_t numSamples = mSamplePointerCoords.size(); - for (size_t i = 0; i < numSamples; i++) { - PointerCoords& c = mSamplePointerCoords.editItemAt(i); - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; - matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point); - c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset); - c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset); - - float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation)); - } -} - -status_t MotionEvent::readFromParcel(Parcel* parcel) { - size_t pointerCount = parcel->readInt32(); - size_t sampleCount = parcel->readInt32(); - if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) { - return BAD_VALUE; - } - - mDeviceId = parcel->readInt32(); - mSource = parcel->readInt32(); - mAction = parcel->readInt32(); - mFlags = parcel->readInt32(); - mEdgeFlags = parcel->readInt32(); - mMetaState = parcel->readInt32(); - mButtonState = parcel->readInt32(); - mXOffset = parcel->readFloat(); - mYOffset = parcel->readFloat(); - mXPrecision = parcel->readFloat(); - mYPrecision = parcel->readFloat(); - mDownTime = parcel->readInt64(); - - mPointerProperties.clear(); - mPointerProperties.setCapacity(pointerCount); - mSampleEventTimes.clear(); - mSampleEventTimes.setCapacity(sampleCount); - mSamplePointerCoords.clear(); - mSamplePointerCoords.setCapacity(sampleCount * pointerCount); - - for (size_t i = 0; i < pointerCount; i++) { - mPointerProperties.push(); - PointerProperties& properties = mPointerProperties.editTop(); - properties.id = parcel->readInt32(); - properties.toolType = parcel->readInt32(); - } - - while (sampleCount-- > 0) { - mSampleEventTimes.push(parcel->readInt64()); - for (size_t i = 0; i < pointerCount; i++) { - mSamplePointerCoords.push(); - status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); - if (status) { - return status; - } - } - } - return OK; -} - -status_t MotionEvent::writeToParcel(Parcel* parcel) const { - size_t pointerCount = mPointerProperties.size(); - size_t sampleCount = mSampleEventTimes.size(); - - parcel->writeInt32(pointerCount); - parcel->writeInt32(sampleCount); - - parcel->writeInt32(mDeviceId); - parcel->writeInt32(mSource); - parcel->writeInt32(mAction); - parcel->writeInt32(mFlags); - parcel->writeInt32(mEdgeFlags); - parcel->writeInt32(mMetaState); - parcel->writeInt32(mButtonState); - parcel->writeFloat(mXOffset); - parcel->writeFloat(mYOffset); - parcel->writeFloat(mXPrecision); - parcel->writeFloat(mYPrecision); - parcel->writeInt64(mDownTime); - - for (size_t i = 0; i < pointerCount; i++) { - const PointerProperties& properties = mPointerProperties.itemAt(i); - parcel->writeInt32(properties.id); - parcel->writeInt32(properties.toolType); - } - - const PointerCoords* pc = mSamplePointerCoords.array(); - for (size_t h = 0; h < sampleCount; h++) { - parcel->writeInt64(mSampleEventTimes.itemAt(h)); - for (size_t i = 0; i < pointerCount; i++) { - status_t status = (pc++)->writeToParcel(parcel); - if (status) { - return status; - } - } - } - return OK; -} -#endif - -bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { - if (source & AINPUT_SOURCE_CLASS_POINTER) { - // Specifically excludes HOVER_MOVE and SCROLL. - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_OUTSIDE: - return true; - } - } - return false; -} - - -// --- PooledInputEventFactory --- - -PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : - mMaxPoolSize(maxPoolSize) { -} - -PooledInputEventFactory::~PooledInputEventFactory() { - for (size_t i = 0; i < mKeyEventPool.size(); i++) { - delete mKeyEventPool.itemAt(i); - } - for (size_t i = 0; i < mMotionEventPool.size(); i++) { - delete mMotionEventPool.itemAt(i); - } -} - -KeyEvent* PooledInputEventFactory::createKeyEvent() { - if (!mKeyEventPool.isEmpty()) { - KeyEvent* event = mKeyEventPool.top(); - mKeyEventPool.pop(); - return event; - } - return new KeyEvent(); -} - -MotionEvent* PooledInputEventFactory::createMotionEvent() { - if (!mMotionEventPool.isEmpty()) { - MotionEvent* event = mMotionEventPool.top(); - mMotionEventPool.pop(); - return event; - } - return new MotionEvent(); -} - -void PooledInputEventFactory::recycle(InputEvent* event) { - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: - if (mKeyEventPool.size() < mMaxPoolSize) { - mKeyEventPool.push(static_cast<KeyEvent*>(event)); - return; - } - break; - case AINPUT_EVENT_TYPE_MOTION: - if (mMotionEventPool.size() < mMaxPoolSize) { - mMotionEventPool.push(static_cast<MotionEvent*>(event)); - return; - } - break; - } - delete event; -} - -} // namespace android diff --git a/widget/gonk/libui/Input.h b/widget/gonk/libui/Input.h deleted file mode 100644 index 3d958bfab..000000000 --- a/widget/gonk/libui/Input.h +++ /dev/null @@ -1,622 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_INPUT_H -#define _ANDROIDFW_INPUT_H - -/** - * Native input event structures. - */ - -#include "android_input.h" -#include <utils/Vector.h> -#include <utils/KeyedVector.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> - -#ifdef HAVE_ANDROID_OS -class SkMatrix; -#endif - -/* - * Additional private constants not defined in ndk/ui/input.h. - */ -enum { - /* Signifies that the key is being predispatched */ - AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000, - - /* Private control to determine when an app is tracking a key sequence. */ - AKEY_EVENT_FLAG_START_TRACKING = 0x40000000, - - /* Key event is inconsistent with previously sent key events. */ - AKEY_EVENT_FLAG_TAINTED = 0x80000000, -}; - -enum { - /* Motion event is inconsistent with previously sent motion events. */ - AMOTION_EVENT_FLAG_TAINTED = 0x80000000, -}; - -enum { - /* Used when a motion event is not associated with any display. - * Typically used for non-pointer events. */ - ADISPLAY_ID_NONE = -1, - - /* The default display id. */ - ADISPLAY_ID_DEFAULT = 0, -}; - -enum { - /* - * Indicates that an input device has switches. - * This input source flag is hidden from the API because switches are only used by the system - * and applications have no way to interact with them. - */ - AINPUT_SOURCE_SWITCH = 0x80000000, -}; - -/* - * SystemUiVisibility constants from View. - */ -enum { - ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0, - ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001, -}; - -/* - * Maximum number of pointers supported per motion event. - * Smallest number of pointers is 1. - * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers - * will occasionally emit 11. There is not much harm making this constant bigger.) - */ -#define MAX_POINTERS 16 - -/* - * Maximum pointer id value supported in a motion event. - * Smallest pointer id is 0. - * (This is limited by our use of BitSet32 to track pointer assignments.) - */ -#define MAX_POINTER_ID 31 - -/* - * Declare a concrete type for the NDK's input event forward declaration. - */ -struct AInputEvent { - virtual ~AInputEvent() { } -}; - -/* - * Declare a concrete type for the NDK's input device forward declaration. - */ -struct AInputDevice { - virtual ~AInputDevice() { } -}; - - -namespace android { - -#ifdef HAVE_ANDROID_OS -class Parcel; -#endif - -/* - * Flags that flow alongside events in the input dispatch system to help with certain - * policy decisions such as waking from device sleep. - * - * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. - */ -enum { - /* These flags originate in RawEvents and are generally set in the key map. - * NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */ - - POLICY_FLAG_WAKE = 0x00000001, - POLICY_FLAG_WAKE_DROPPED = 0x00000002, - POLICY_FLAG_SHIFT = 0x00000004, - POLICY_FLAG_CAPS_LOCK = 0x00000008, - POLICY_FLAG_ALT = 0x00000010, - POLICY_FLAG_ALT_GR = 0x00000020, - POLICY_FLAG_MENU = 0x00000040, - POLICY_FLAG_LAUNCHER = 0x00000080, - POLICY_FLAG_VIRTUAL = 0x00000100, - POLICY_FLAG_FUNCTION = 0x00000200, - - POLICY_FLAG_RAW_MASK = 0x0000ffff, - - /* These flags are set by the input dispatcher. */ - - // Indicates that the input event was injected. - POLICY_FLAG_INJECTED = 0x01000000, - - // Indicates that the input event is from a trusted source such as a directly attached - // input device or an application with system-wide event injection permission. - POLICY_FLAG_TRUSTED = 0x02000000, - - // Indicates that the input event has passed through an input filter. - POLICY_FLAG_FILTERED = 0x04000000, - - // Disables automatic key repeating behavior. - POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000, - - /* These flags are set by the input reader policy as it intercepts each event. */ - - // Indicates that the screen was off when the event was received and the event - // should wake the device. - POLICY_FLAG_WOKE_HERE = 0x10000000, - - // Indicates that the screen was dim when the event was received and the event - // should brighten the device. - POLICY_FLAG_BRIGHT_HERE = 0x20000000, - - // Indicates that the event should be dispatched to applications. - // The input event should still be sent to the InputDispatcher so that it can see all - // input events received include those that it will not deliver. - POLICY_FLAG_PASS_TO_USER = 0x40000000, -}; - -/* - * Pointer coordinate data. - */ -struct PointerCoords { - enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64 - - // Bitfield of axes that are present in this structure. - uint64_t bits; - - // Values of axes that are stored in this structure packed in order by axis id - // for each axis that is present in the structure according to 'bits'. - float values[MAX_AXES]; - - inline void clear() { - bits = 0; - } - - float getAxisValue(int32_t axis) const; - status_t setAxisValue(int32_t axis, float value); - - void scale(float scale); - - inline float getX() const { - return getAxisValue(AMOTION_EVENT_AXIS_X); - } - - inline float getY() const { - return getAxisValue(AMOTION_EVENT_AXIS_Y); - } - -#ifdef HAVE_ANDROID_OS - status_t readFromParcel(Parcel* parcel); - status_t writeToParcel(Parcel* parcel) const; -#endif - - bool operator==(const PointerCoords& other) const; - inline bool operator!=(const PointerCoords& other) const { - return !(*this == other); - } - - void copyFrom(const PointerCoords& other); - -private: - void tooManyAxes(int axis); -}; - -/* - * Pointer property data. - */ -struct PointerProperties { - // The id of the pointer. - int32_t id; - - // The pointer tool type. - int32_t toolType; - - inline void clear() { - id = -1; - toolType = 0; - } - - bool operator==(const PointerProperties& other) const; - inline bool operator!=(const PointerProperties& other) const { - return !(*this == other); - } - - void copyFrom(const PointerProperties& other); -}; - -/* - * Input events. - */ -class InputEvent : public AInputEvent { -public: - virtual ~InputEvent() { } - - virtual int32_t getType() const = 0; - - inline int32_t getDeviceId() const { return mDeviceId; } - - inline int32_t getSource() const { return mSource; } - - inline void setSource(int32_t source) { mSource = source; } - -protected: - void initialize(int32_t deviceId, int32_t source); - void initialize(const InputEvent& from); - - int32_t mDeviceId; - int32_t mSource; -}; - -/* - * Key events. - */ -class KeyEvent : public InputEvent { -public: - virtual ~KeyEvent() { } - - virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; } - - inline int32_t getAction() const { return mAction; } - - inline int32_t getFlags() const { return mFlags; } - - inline void setFlags(int32_t flags) { mFlags = flags; } - - inline int32_t getKeyCode() const { return mKeyCode; } - - inline int32_t getScanCode() const { return mScanCode; } - - inline int32_t getMetaState() const { return mMetaState; } - - inline int32_t getRepeatCount() const { return mRepeatCount; } - - inline nsecs_t getDownTime() const { return mDownTime; } - - inline nsecs_t getEventTime() const { return mEventTime; } - - // Return true if this event may have a default action implementation. - static bool hasDefaultAction(int32_t keyCode); - bool hasDefaultAction() const; - - // Return true if this event represents a system key. - static bool isSystemKey(int32_t keyCode); - bool isSystemKey() const; - - void initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime); - void initialize(const KeyEvent& from); - -protected: - int32_t mAction; - int32_t mFlags; - int32_t mKeyCode; - int32_t mScanCode; - int32_t mMetaState; - int32_t mRepeatCount; - nsecs_t mDownTime; - nsecs_t mEventTime; -}; - -/* - * Motion events. - */ -class MotionEvent : public InputEvent { -public: - virtual ~MotionEvent() { } - - virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; } - - inline int32_t getAction() const { return mAction; } - - inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } - - inline int32_t getActionIndex() const { - return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - inline void setAction(int32_t action) { mAction = action; } - - inline int32_t getFlags() const { return mFlags; } - - inline void setFlags(int32_t flags) { mFlags = flags; } - - inline int32_t getEdgeFlags() const { return mEdgeFlags; } - - inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; } - - inline int32_t getMetaState() const { return mMetaState; } - - inline void setMetaState(int32_t metaState) { mMetaState = metaState; } - - inline int32_t getButtonState() const { return mButtonState; } - - inline float getXOffset() const { return mXOffset; } - - inline float getYOffset() const { return mYOffset; } - - inline float getXPrecision() const { return mXPrecision; } - - inline float getYPrecision() const { return mYPrecision; } - - inline nsecs_t getDownTime() const { return mDownTime; } - - inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } - - inline size_t getPointerCount() const { return mPointerProperties.size(); } - - inline const PointerProperties* getPointerProperties(size_t pointerIndex) const { - return &mPointerProperties[pointerIndex]; - } - - inline int32_t getPointerId(size_t pointerIndex) const { - return mPointerProperties[pointerIndex].id; - } - - inline int32_t getToolType(size_t pointerIndex) const { - return mPointerProperties[pointerIndex].toolType; - } - - inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } - - const PointerCoords* getRawPointerCoords(size_t pointerIndex) const; - - float getRawAxisValue(int32_t axis, size_t pointerIndex) const; - - inline float getRawX(size_t pointerIndex) const { - return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); - } - - inline float getRawY(size_t pointerIndex) const { - return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); - } - - float getAxisValue(int32_t axis, size_t pointerIndex) const; - - inline float getX(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); - } - - inline float getY(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); - } - - inline float getPressure(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex); - } - - inline float getSize(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex); - } - - inline float getTouchMajor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex); - } - - inline float getTouchMinor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex); - } - - inline float getToolMajor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex); - } - - inline float getToolMinor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex); - } - - inline float getOrientation(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex); - } - - inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; } - - inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const { - return mSampleEventTimes[historicalIndex]; - } - - const PointerCoords* getHistoricalRawPointerCoords( - size_t pointerIndex, size_t historicalIndex) const; - - float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const; - - inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalRawAxisValue( - AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); - } - - inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalRawAxisValue( - AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); - } - - float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const; - - inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); - } - - inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); - } - - inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex); - } - - inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex); - } - - inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex); - } - - ssize_t findPointerIndex(int32_t pointerId) const; - - void initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); - - void copyFrom(const MotionEvent* other, bool keepHistory); - - void addSample( - nsecs_t eventTime, - const PointerCoords* pointerCoords); - - void offsetLocation(float xOffset, float yOffset); - - void scale(float scaleFactor); - -#ifdef HAVE_ANDROID_OS - void transform(const SkMatrix* matrix); - - status_t readFromParcel(Parcel* parcel); - status_t writeToParcel(Parcel* parcel) const; -#endif - - static bool isTouchEvent(int32_t source, int32_t action); - inline bool isTouchEvent() const { - return isTouchEvent(mSource, mAction); - } - - // Low-level accessors. - inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); - } - inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } - inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); - } - -protected: - int32_t mAction; - int32_t mFlags; - int32_t mEdgeFlags; - int32_t mMetaState; - int32_t mButtonState; - float mXOffset; - float mYOffset; - float mXPrecision; - float mYPrecision; - nsecs_t mDownTime; - Vector<PointerProperties> mPointerProperties; - Vector<nsecs_t> mSampleEventTimes; - Vector<PointerCoords> mSamplePointerCoords; -}; - -/* - * Input event factory. - */ -class InputEventFactoryInterface { -protected: - virtual ~InputEventFactoryInterface() { } - -public: - InputEventFactoryInterface() { } - - virtual KeyEvent* createKeyEvent() = 0; - virtual MotionEvent* createMotionEvent() = 0; -}; - -/* - * A simple input event factory implementation that uses a single preallocated instance - * of each type of input event that are reused for each request. - */ -class PreallocatedInputEventFactory : public InputEventFactoryInterface { -public: - PreallocatedInputEventFactory() { } - virtual ~PreallocatedInputEventFactory() { } - - virtual KeyEvent* createKeyEvent() { return & mKeyEvent; } - virtual MotionEvent* createMotionEvent() { return & mMotionEvent; } - -private: - KeyEvent mKeyEvent; - MotionEvent mMotionEvent; -}; - -/* - * An input event factory implementation that maintains a pool of input events. - */ -class PooledInputEventFactory : public InputEventFactoryInterface { -public: - PooledInputEventFactory(size_t maxPoolSize = 20); - virtual ~PooledInputEventFactory(); - - virtual KeyEvent* createKeyEvent(); - virtual MotionEvent* createMotionEvent(); - - void recycle(InputEvent* event); - -private: - const size_t mMaxPoolSize; - - Vector<KeyEvent*> mKeyEventPool; - Vector<MotionEvent*> mMotionEventPool; -}; - -} // namespace android - -#endif // _ANDROIDFW_INPUT_H diff --git a/widget/gonk/libui/InputApplication.cpp b/widget/gonk/libui/InputApplication.cpp deleted file mode 100644 index ce432356b..000000000 --- a/widget/gonk/libui/InputApplication.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputApplication" - -#include "InputApplication.h" - -#include "cutils_log.h" - -namespace android { - -// --- InputApplicationHandle --- - -InputApplicationHandle::InputApplicationHandle() : - mInfo(NULL) { -} - -InputApplicationHandle::~InputApplicationHandle() { - delete mInfo; -} - -void InputApplicationHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = NULL; - } -} - -} // namespace android diff --git a/widget/gonk/libui/InputApplication.h b/widget/gonk/libui/InputApplication.h deleted file mode 100644 index ba789559c..000000000 --- a/widget/gonk/libui/InputApplication.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_INPUT_APPLICATION_H -#define _UI_INPUT_APPLICATION_H - -#include "Input.h" - -#include <utils/RefBase.h> -#include <utils/Timers.h> -#include <utils/String8.h> - -namespace android { - -/* - * Describes the properties of an application that can receive input. - */ -struct InputApplicationInfo { - String8 name; - nsecs_t dispatchingTimeout; -}; - - -/* - * Handle for an application that can receive input. - * - * Used by the native input dispatcher as a handle for the window manager objects - * that describe an application. - */ -class InputApplicationHandle : public RefBase { -public: - inline const InputApplicationInfo* getInfo() const { - return mInfo; - } - - inline String8 getName() const { - return mInfo ? mInfo->name : String8("<invalid>"); - } - - inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - - /** - * Releases the storage used by the associated information when it is - * no longer needed. - */ - void releaseInfo(); - -protected: - InputApplicationHandle(); - virtual ~InputApplicationHandle(); - - InputApplicationInfo* mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_APPLICATION_H diff --git a/widget/gonk/libui/InputDevice.cpp b/widget/gonk/libui/InputDevice.cpp deleted file mode 100644 index 01a437dd4..000000000 --- a/widget/gonk/libui/InputDevice.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputDevice" - -#include <stdlib.h> -#include <unistd.h> -#include <ctype.h> - -#include "InputDevice.h" - -namespace android { - -static const char* CONFIGURATION_FILE_DIR[] = { - "idc/", - "keylayout/", - "keychars/", -}; - -static const char* CONFIGURATION_FILE_EXTENSION[] = { - ".idc", - ".kl", - ".kcm", -}; - -static bool isValidNameChar(char ch) { - return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); -} - -static void appendInputDeviceConfigurationFileRelativePath(String8& path, - const String8& name, InputDeviceConfigurationFileType type) { - path.append(CONFIGURATION_FILE_DIR[type]); - for (size_t i = 0; i < name.length(); i++) { - char ch = name[i]; - if (!isValidNameChar(ch)) { - ch = '_'; - } - path.append(&ch, 1); - } - path.append(CONFIGURATION_FILE_EXTENSION[type]); -} - -String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( - const InputDeviceIdentifier& deviceIdentifier, - InputDeviceConfigurationFileType type) { - if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { - if (deviceIdentifier.version != 0) { - // Try vendor product version. - String8 versionPath(getInputDeviceConfigurationFilePathByName( - String8::format("Vendor_%04x_Product_%04x_Version_%04x", - deviceIdentifier.vendor, deviceIdentifier.product, - deviceIdentifier.version), - type)); - if (!versionPath.isEmpty()) { - return versionPath; - } - } - - // Try vendor product. - String8 productPath(getInputDeviceConfigurationFilePathByName( - String8::format("Vendor_%04x_Product_%04x", - deviceIdentifier.vendor, deviceIdentifier.product), - type)); - if (!productPath.isEmpty()) { - return productPath; - } - } - - // Try device name. - return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); -} - -String8 getInputDeviceConfigurationFilePathByName( - const String8& name, InputDeviceConfigurationFileType type) { - // Search system repository. - String8 path; - path.setTo(getenv("ANDROID_ROOT")); - path.append("/usr/"); - appendInputDeviceConfigurationFileRelativePath(path, name, type); -#if DEBUG_PROBE - ALOGD("Probing for system provided input device configuration file: path='%s'", path.string()); -#endif - if (!access(path.string(), R_OK)) { -#if DEBUG_PROBE - ALOGD("Found"); -#endif - return path; - } - - // Search user repository. - // TODO Should only look here if not in safe mode. - path.setTo(getenv("ANDROID_DATA")); - path.append("/system/devices/"); - appendInputDeviceConfigurationFileRelativePath(path, name, type); -#if DEBUG_PROBE - ALOGD("Probing for system user input device configuration file: path='%s'", path.string()); -#endif - if (!access(path.string(), R_OK)) { -#if DEBUG_PROBE - ALOGD("Found"); -#endif - return path; - } - - // Not found. -#if DEBUG_PROBE - ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", - name.string(), type); -#endif - return String8(); -} - - -// --- InputDeviceInfo --- - -InputDeviceInfo::InputDeviceInfo() { - initialize(-1, -1, InputDeviceIdentifier(), String8(), false); -} - -InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : - mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier), - mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources), - mKeyboardType(other.mKeyboardType), - mKeyCharacterMap(other.mKeyCharacterMap), - mHasVibrator(other.mHasVibrator), - mMotionRanges(other.mMotionRanges) { -} - -InputDeviceInfo::~InputDeviceInfo() { -} - -void InputDeviceInfo::initialize(int32_t id, int32_t generation, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { - mId = id; - mGeneration = generation; - mIdentifier = identifier; - mAlias = alias; - mIsExternal = isExternal; - mSources = 0; - mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; - mHasVibrator = false; - mMotionRanges.clear(); -} - -const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( - int32_t axis, uint32_t source) const { - size_t numRanges = mMotionRanges.size(); - for (size_t i = 0; i < numRanges; i++) { - const MotionRange& range = mMotionRanges.itemAt(i); - if (range.axis == axis && range.source == source) { - return ⦥ - } - } - return NULL; -} - -void InputDeviceInfo::addSource(uint32_t source) { - mSources |= source; -} - -void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, - float flat, float fuzz, float resolution) { - MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; - mMotionRanges.add(range); -} - -void InputDeviceInfo::addMotionRange(const MotionRange& range) { - mMotionRanges.add(range); -} - -} // namespace android diff --git a/widget/gonk/libui/InputDevice.h b/widget/gonk/libui/InputDevice.h deleted file mode 100644 index 0ab5863c9..000000000 --- a/widget/gonk/libui/InputDevice.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_INPUT_DEVICE_H -#define _ANDROIDFW_INPUT_DEVICE_H - -#include "Input.h" -#include "KeyCharacterMap.h" - -namespace android { - -/* - * Identifies a device. - */ -struct InputDeviceIdentifier { - inline InputDeviceIdentifier() : - bus(0), vendor(0), product(0), version(0) { - } - - // Information provided by the kernel. - String8 name; - String8 location; - String8 uniqueId; - uint16_t bus; - uint16_t vendor; - uint16_t product; - uint16_t version; - - // A composite input device descriptor string that uniquely identifies the device - // even across reboots or reconnections. The value of this field is used by - // upper layers of the input system to associate settings with individual devices. - // It is hashed from whatever kernel provided information is available. - // Ideally, the way this value is computed should not change between Android releases - // because that would invalidate persistent settings that rely on it. - String8 descriptor; -}; - -/* - * Describes the characteristics and capabilities of an input device. - */ -class InputDeviceInfo { -public: - InputDeviceInfo(); - InputDeviceInfo(const InputDeviceInfo& other); - ~InputDeviceInfo(); - - struct MotionRange { - int32_t axis; - uint32_t source; - float min; - float max; - float flat; - float fuzz; - float resolution; - }; - - void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, - const String8& alias, bool isExternal); - - inline int32_t getId() const { return mId; } - inline int32_t getGeneration() const { return mGeneration; } - inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; } - inline const String8& getAlias() const { return mAlias; } - inline const String8& getDisplayName() const { - return mAlias.isEmpty() ? mIdentifier.name : mAlias; - } - inline bool isExternal() const { return mIsExternal; } - inline uint32_t getSources() const { return mSources; } - - const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; - - void addSource(uint32_t source); - void addMotionRange(int32_t axis, uint32_t source, - float min, float max, float flat, float fuzz, float resolution); - void addMotionRange(const MotionRange& range); - - inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } - inline int32_t getKeyboardType() const { return mKeyboardType; } - - inline void setKeyCharacterMap(const sp<KeyCharacterMap>& value) { - mKeyCharacterMap = value; - } - - inline sp<KeyCharacterMap> getKeyCharacterMap() const { - return mKeyCharacterMap; - } - - inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } - inline bool hasVibrator() const { return mHasVibrator; } - - inline const Vector<MotionRange>& getMotionRanges() const { - return mMotionRanges; - } - -private: - int32_t mId; - int32_t mGeneration; - InputDeviceIdentifier mIdentifier; - String8 mAlias; - bool mIsExternal; - uint32_t mSources; - int32_t mKeyboardType; - sp<KeyCharacterMap> mKeyCharacterMap; - bool mHasVibrator; - - Vector<MotionRange> mMotionRanges; -}; - -/* Types of input device configuration files. */ -enum InputDeviceConfigurationFileType { - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */ - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */ - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */ -}; - -/* - * Gets the path of an input device configuration file, if one is available. - * Considers both system provided and user installed configuration files. - * - * The device identifier is used to construct several default configuration file - * names to try based on the device name, vendor, product, and version. - * - * Returns an empty string if not found. - */ -extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( - const InputDeviceIdentifier& deviceIdentifier, - InputDeviceConfigurationFileType type); - -/* - * Gets the path of an input device configuration file, if one is available. - * Considers both system provided and user installed configuration files. - * - * The name is case-sensitive and is used to construct the filename to resolve. - * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores. - * - * Returns an empty string if not found. - */ -extern String8 getInputDeviceConfigurationFilePathByName( - const String8& name, InputDeviceConfigurationFileType type); - -} // namespace android - -#endif // _ANDROIDFW_INPUT_DEVICE_H diff --git a/widget/gonk/libui/InputDispatcher.cpp b/widget/gonk/libui/InputDispatcher.cpp deleted file mode 100644 index 7adaa1998..000000000 --- a/widget/gonk/libui/InputDispatcher.cpp +++ /dev/null @@ -1,4430 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputDispatcher" -#define ATRACE_TAG ATRACE_TAG_INPUT - -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -// Log detailed debug messages about each inbound event notification to the dispatcher. -#define DEBUG_INBOUND_EVENT_DETAILS 0 - -// Log detailed debug messages about each outbound event processed by the dispatcher. -#define DEBUG_OUTBOUND_EVENT_DETAILS 0 - -// Log debug messages about the dispatch cycle. -#define DEBUG_DISPATCH_CYCLE 0 - -// Log debug messages about registrations. -#define DEBUG_REGISTRATION 0 - -// Log debug messages about input event injection. -#define DEBUG_INJECTION 0 - -// Log debug messages about input focus tracking. -#define DEBUG_FOCUS 0 - -// Log debug messages about the app switch latency optimization. -#define DEBUG_APP_SWITCH 0 - -// Log debug messages about hover events. -#define DEBUG_HOVER 0 - -#include "InputDispatcher.h" - -#include "Trace.h" -#include "PowerManager.h" - -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> -#include <time.h> - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " - -namespace android { - -// Default input dispatching timeout if there is no focused application or paused window -// from which to determine an appropriate dispatching timeout. -const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec - -// Amount of time to allow for all pending events to be processed when an app switch -// key is on the way. This is used to preempt input dispatch and drop input events -// when an application takes too long to respond and the user has pressed an app switch key. -const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec - -// Amount of time to allow for an event to be dispatched (measured since its eventTime) -// before considering it stale and dropping it. -const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec - -// Amount of time to allow touch events to be streamed out to a connection before requiring -// that the first event be finished. This value extends the ANR timeout by the specified -// amount. For example, if streaming is allowed to get ahead by one second relative to the -// queue of waiting unfinished events, then ANRs will similarly be delayed by one second. -const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec - -// Log a warning when an event takes longer than this to process, even if an ANR does not occur. -const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec - - -static inline nsecs_t now() { - return systemTime(SYSTEM_TIME_MONOTONIC); -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -} - -static bool isValidKeyAction(int32_t action) { - switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; - } -} - -static bool validateKeyEvent(int32_t action) { - if (! isValidKeyAction(action)) { - ALOGE("Key event has invalid action code 0x%x", action); - return false; - } - return true; -} - -static bool isValidMotionAction(int32_t action, size_t pointerCount) { - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_SCROLL: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && size_t(index) < pointerCount; - } - default: - return false; - } -} - -static bool validateMotionEvent(int32_t action, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, pointerCount)) { - ALOGE("Motion event has invalid action code 0x%x", action); - return false; - } - if (pointerCount < 1 || pointerCount > MAX_POINTERS) { - ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); - return false; - } - BitSet32 pointerIdBits; - for (size_t i = 0; i < pointerCount; i++) { - int32_t id = pointerProperties[i].id; - if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - id, MAX_POINTER_ID); - return false; - } - if (pointerIdBits.hasBit(id)) { - ALOGE("Motion event has duplicate pointer id %d", id); - return false; - } - pointerIdBits.markBit(id); - } - return true; -} - -static bool isMainDisplay(int32_t displayId) { - return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE; -} - -static void dumpRegion(String8& dump, const SkRegion& region) { - if (region.isEmpty()) { - dump.append("<empty>"); - return; - } - - bool first = true; - for (SkRegion::Iterator it(region); !it.done(); it.next()) { - if (first) { - first = false; - } else { - dump.append("|"); - } - const SkIRect& rect = it.rect(); - dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - } -} - - -// --- InputDispatcher --- - -InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : - mPolicy(policy), - mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(NULL), - mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { - mLooper = new Looper(false); - - mKeyRepeatState.lastKeyEntry = NULL; - - policy->getDispatcherConfiguration(&mConfig); -} - -InputDispatcher::~InputDispatcher() { - { // acquire lock - AutoMutex _l(mLock); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - } - - while (mConnectionsByFd.size() != 0) { - unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); - } -} - -void InputDispatcher::dispatchOnce() { - nsecs_t nextWakeupTime = LONG_LONG_MAX; - { // acquire lock - AutoMutex _l(mLock); - mDispatcherIsAliveCondition.broadcast(); - - // Run a dispatch loop if there are no pending commands. - // The dispatch loop might enqueue commands to run afterwards. - if (!haveCommandsLocked()) { - dispatchOnceInnerLocked(&nextWakeupTime); - } - - // Run all pending commands if there are any. - // If any commands were run then force the next poll to wake up immediately. - if (runCommandsLockedInterruptible()) { - nextWakeupTime = LONG_LONG_MIN; - } - } // release lock - - // Wait for callback or timeout or wake. (make sure we round up, not down) - nsecs_t currentTime = now(); - int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); - mLooper->pollOnce(timeoutMillis); -} - -void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { - nsecs_t currentTime = now(); - - // Reset the key repeat timer whenever we disallow key events, even if the next event - // is not a key. This is to ensure that we abort a key repeat if the device is just coming - // out of sleep. - if (!mPolicy->isKeyRepeatEnabled()) { - resetKeyRepeatLocked(); - } - - // If dispatching is frozen, do not process timeouts or try to deliver any new events. - if (mDispatchFrozen) { -#if DEBUG_FOCUS - ALOGD("Dispatch frozen. Waiting some more."); -#endif - return; - } - - // Optimize latency of app switches. - // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has - // been pressed. When it expires, we preempt dispatch and drop all other pending events. - bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; - if (mAppSwitchDueTime < *nextWakeupTime) { - *nextWakeupTime = mAppSwitchDueTime; - } - - // Ready to start a new event. - // If we don't already have a pending event, go grab one. - if (! mPendingEvent) { - if (mInboundQueue.isEmpty()) { - if (isAppSwitchDue) { - // The inbound queue is empty so the app switch key we were waiting - // for will never arrive. Stop waiting for it. - resetPendingAppSwitchLocked(false); - isAppSwitchDue = false; - } - - // Synthesize a key repeat if appropriate. - if (mKeyRepeatState.lastKeyEntry) { - if (currentTime >= mKeyRepeatState.nextRepeatTime) { - mPendingEvent = synthesizeKeyRepeatLocked(currentTime); - } else { - if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { - *nextWakeupTime = mKeyRepeatState.nextRepeatTime; - } - } - } - - // Nothing to do if there is no pending event. - if (!mPendingEvent) { - return; - } - } else { - // Inbound queue has at least one entry. - mPendingEvent = mInboundQueue.dequeueAtHead(); - traceInboundQueueLengthLocked(); - } - - // Poke user activity for this event. - if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { - pokeUserActivityLocked(mPendingEvent); - } - - // Get ready to dispatch the event. - resetANRTimeoutsLocked(); - } - - // Now we have an event to dispatch. - // All events are eventually dequeued and processed this way, even if we intend to drop them. - ALOG_ASSERT(mPendingEvent != NULL); - bool done = false; - DropReason dropReason = DROP_REASON_NOT_DROPPED; - if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { - dropReason = DROP_REASON_POLICY; - } else if (!mDispatchEnabled) { - dropReason = DROP_REASON_DISABLED; - } - - if (mNextUnblockedEvent == mPendingEvent) { - mNextUnblockedEvent = NULL; - } - - switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast<ConfigurationChangedEntry*>(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; - } - - case EventEntry::TYPE_DEVICE_RESET: { - DeviceResetEntry* typedEntry = - static_cast<DeviceResetEntry*>(mPendingEvent); - done = dispatchDeviceResetLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped - break; - } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEventLocked(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEventLocked(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEventLocked(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchMotionLocked(currentTime, typedEntry, - &dropReason, nextWakeupTime); - break; - } - - default: - ALOG_ASSERT(false); - break; - } - - if (done) { - if (dropReason != DROP_REASON_NOT_DROPPED) { - dropInboundEventLocked(mPendingEvent, dropReason); - } - - releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately - } -} - -bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { - bool needWake = mInboundQueue.isEmpty(); - mInboundQueue.enqueueAtTail(entry); - traceInboundQueueLengthLocked(); - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - // Optimize app switch latency. - // If the application takes too long to catch up then we drop all events preceding - // the app switch key. - KeyEntry* keyEntry = static_cast<KeyEntry*>(entry); - if (isAppSwitchKeyEventLocked(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { -#if DEBUG_APP_SWITCH - ALOGD("App switch is pending!"); -#endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; - } - } - } - break; - } - - case EventEntry::TYPE_MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN - && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplicationHandle != NULL) { - int32_t displayId = motionEntry->displayId; - int32_t x = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (touchedWindowHandle != NULL - && touchedWindowHandle->inputApplicationHandle - != mInputTargetWaitApplicationHandle) { - // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - mNextUnblockedEvent = motionEntry; - needWake = true; - } - } - break; - } - } - - return needWake; -} - -sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, - int32_t x, int32_t y) { - // Traverse windows from front to back to find touched window. - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId == displayId) { - int32_t flags = windowInfo->layoutParamsFlags; - - if (windowInfo->visible) { - if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - // Found window. - return windowHandle; - } - } - } - - if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) { - // Error window is on top but not visible, so touch is dropped. - return NULL; - } - } - } - return NULL; -} - -void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { - const char* reason; - switch (dropReason) { - case DROP_REASON_POLICY: -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("Dropped event because policy consumed it."); -#endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - ALOGI("Dropped event because input dispatch is disabled."); - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - ALOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - case DROP_REASON_BLOCKED: - ALOGI("Dropped event because the current application is not responding and the user " - "has started interacting with a different application."); - reason = "inbound event was dropped because the current application is not responding " - "and the user has started interacting with a different application"; - break; - case DROP_REASON_STALE: - ALOGI("Dropped event because it is stale."); - reason = "inbound event was dropped because it is stale"; - break; - default: - ALOG_ASSERT(false); - return; - } - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } else { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - break; - } - } -} - -bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME - || keyCode == AKEYCODE_ENDCALL - || keyCode == AKEYCODE_APP_SWITCH; -} - -bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { - return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKeyCode(keyEntry->keyCode) - && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) - && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); -} - -bool InputDispatcher::isAppSwitchPendingLocked() { - return mAppSwitchDueTime != LONG_LONG_MAX; -} - -void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { - mAppSwitchDueTime = LONG_LONG_MAX; - -#if DEBUG_APP_SWITCH - if (handled) { - ALOGD("App switch has arrived."); - } else { - ALOGD("App switch was abandoned."); - } -#endif -} - -bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { - return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; -} - -bool InputDispatcher::haveCommandsLocked() const { - return !mCommandQueue.isEmpty(); -} - -bool InputDispatcher::runCommandsLockedInterruptible() { - if (mCommandQueue.isEmpty()) { - return false; - } - - do { - CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); - - Command command = commandEntry->command; - (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' - - commandEntry->connection.clear(); - delete commandEntry; - } while (! mCommandQueue.isEmpty()); - return true; -} - -InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { - CommandEntry* commandEntry = new CommandEntry(command); - mCommandQueue.enqueueAtTail(commandEntry); - return commandEntry; -} - -void InputDispatcher::drainInboundQueueLocked() { - while (! mInboundQueue.isEmpty()) { - EventEntry* entry = mInboundQueue.dequeueAtHead(); - releaseInboundEventLocked(entry); - } - traceInboundQueueLengthLocked(); -} - -void InputDispatcher::releasePendingEventLocked() { - if (mPendingEvent) { - resetANRTimeoutsLocked(); - releaseInboundEventLocked(mPendingEvent); - mPendingEvent = NULL; - } -} - -void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("Injected inbound event was dropped."); -#endif - setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); - } - if (entry == mNextUnblockedEvent) { - mNextUnblockedEvent = NULL; - } - entry->release(); -} - -void InputDispatcher::resetKeyRepeatLocked() { - if (mKeyRepeatState.lastKeyEntry) { - mKeyRepeatState.lastKeyEntry->release(); - mKeyRepeatState.lastKeyEntry = NULL; - } -} - -InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { - KeyEntry* entry = mKeyRepeatState.lastKeyEntry; - - // Reuse the repeated key entry if it is otherwise unreferenced. - uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) - | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; - if (entry->refCount == 1) { - entry->recycle(); - entry->eventTime = currentTime; - entry->policyFlags = policyFlags; - entry->repeatCount += 1; - } else { - KeyEntry* newEntry = new KeyEntry(currentTime, - entry->deviceId, entry->source, policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount + 1, entry->downTime); - - mKeyRepeatState.lastKeyEntry = newEntry; - entry->release(); - - entry = newEntry; - } - entry->syntheticRepeat = true; - - // Increment reference count since we keep a reference to the event in - // mKeyRepeatState.lastKeyEntry in addition to the one we return. - entry->refCount += 1; - - mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; - return entry; -} - -bool InputDispatcher::dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); -#endif - - // Reset key repeating in case a keyboard device was added or removed or something. - resetKeyRepeatLocked(); - - // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyConfigurationChangedInterruptible); - commandEntry->eventTime = entry->eventTime; - return true; -} - -bool InputDispatcher::dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); -#endif - - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "device was reset"); - options.deviceId = entry->deviceId; - synthesizeCancelationEventsForAllConnectionsLocked(options); - return true; -} - -bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - if (entry->repeatCount == 0 - && entry->action == AKEY_EVENT_ACTION_DOWN - && (entry->policyFlags & POLICY_FLAG_TRUSTED) - && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { - if (mKeyRepeatState.lastKeyEntry - && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { - // We have seen two identical key downs in a row which indicates that the device - // driver is automatically generating key repeats itself. We take note of the - // repeat here, but we disable our own next key repeat timer since it is clear that - // we will not need to synthesize key repeats ourselves. - entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves - } else { - // Not a repeat. Save key down state in case we do see a repeat later. - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; - } - mKeyRepeatState.lastKeyEntry = entry; - entry->refCount += 1; - } else if (! entry->syntheticRepeat) { - resetKeyRepeatLocked(); - } - - if (entry->repeatCount == 1) { - entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; - } else { - entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; - } - - entry->dispatchInProgress = true; - - logOutboundKeyDetailsLocked("dispatchKey - ", entry); - } - - // Handle case where the policy asked us to try again later last time. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { - if (currentTime < entry->interceptKeyWakeupTime) { - if (entry->interceptKeyWakeupTime < *nextWakeupTime) { - *nextWakeupTime = entry->interceptKeyWakeupTime; - } - return false; // wait until next wakeup - } - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - entry->interceptKeyWakeupTime = 0; - } - - // Give the policy a chance to intercept the key. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { - if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (mFocusedWindowHandle != NULL) { - commandEntry->inputWindowHandle = mFocusedWindowHandle; - } - commandEntry->keyEntry = entry; - entry->refCount += 1; - return false; // wait for the command to run - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } - } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { - if (*dropReason == DROP_REASON_NOT_DROPPED) { - *dropReason = DROP_REASON_POLICY; - } - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - // Identify targets. - Vector<InputTarget> inputTargets; - int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - addMonitoringTargetsLocked(inputTargets); - - // Dispatch the key. - dispatchEventLocked(currentTime, entry, inputTargets); - return true; -} - -void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " - "repeatCount=%d, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); -#endif -} - -bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - entry->dispatchInProgress = true; - - logOutboundMotionDetailsLocked("dispatchMotion - ", entry); - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; - - // Identify targets. - Vector<InputTarget> inputTargets; - - bool conflictingPointerActions = false; - int32_t injectionResult; - if (isPointerEvent) { - // Pointer event. (eg. touchscreen) - injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime, &conflictingPointerActions); - } else { - // Non touch event. (eg. trackball) - injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); - } - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - // TODO: support sending secondary display events to input monitors - if (isMainDisplay(entry->displayId)) { - addMonitoringTargetsLocked(inputTargets); - } - - // Dispatch the motion. - if (conflictingPointerActions) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - dispatchEventLocked(currentTime, entry, inputTargets); - return true; -} - - -void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x, " - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, - entry->metaState, entry->buttonState, - entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); - - for (uint32_t i = 0; i < entry->pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerProperties[i].id, - entry->pointerProperties[i].toolType, - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } -#endif -} - -void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, - EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("dispatchEventToCurrentInputTargets"); -#endif - - ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true - - pokeUserActivityLocked(eventEntry); - - for (size_t i = 0; i < inputTargets.size(); i++) { - const InputTarget& inputTarget = inputTargets.itemAt(i); - - ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); - } else { -#if DEBUG_FOCUS - ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().string()); -#endif - } - } -} - -int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) { - if (applicationHandle == NULL && windowHandle == NULL) { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { -#if DEBUG_FOCUS - ALOGD("Waiting for system to become ready for input. Reason: %s", reason); -#endif - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = LONG_LONG_MAX; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); - } - } else { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { -#if DEBUG_FOCUS - ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), - reason); -#endif - nsecs_t timeout; - if (windowHandle != NULL) { - timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else if (applicationHandle != NULL) { - timeout = applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else { - timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; - } - - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = currentTime + timeout; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); - - if (windowHandle != NULL) { - mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; - } - if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { - mInputTargetWaitApplicationHandle = applicationHandle; - } - } - } - - if (mInputTargetWaitTimeoutExpired) { - return INPUT_EVENT_INJECTION_TIMED_OUT; - } - - if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, applicationHandle, windowHandle, - entry->eventTime, mInputTargetWaitStartTime, reason); - - // Force poll loop to wake up immediately on next iteration once we get the - // ANR response back from the policy. - *nextWakeupTime = LONG_LONG_MIN; - return INPUT_EVENT_INJECTION_PENDING; - } else { - // Force poll loop to wake up when timeout is due. - if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { - *nextWakeupTime = mInputTargetWaitTimeoutTime; - } - return INPUT_EVENT_INJECTION_PENDING; - } -} - -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel) { - if (newTimeout > 0) { - // Extend the timeout. - mInputTargetWaitTimeoutTime = now() + newTimeout; - } else { - // Give up. - mInputTargetWaitTimeoutExpired = true; - - // Input state will not be realistic. Mark it out of sync. - if (inputChannel.get()) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - sp<InputWindowHandle> windowHandle = connection->inputWindowHandle; - - if (windowHandle != NULL) { - mTouchState.removeWindow(windowHandle); - } - - if (connection->status == Connection::STATUS_NORMAL) { - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - } - } - } -} - -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( - nsecs_t currentTime) { - if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { - return currentTime - mInputTargetWaitStartTime; - } - return 0; -} - -void InputDispatcher::resetANRTimeoutsLocked() { -#if DEBUG_FOCUS - ALOGD("Resetting ANR timeouts."); -#endif - - // Reset input target wait timeout. - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; - mInputTargetWaitApplicationHandle.clear(); -} - -int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { - int32_t injectionResult; - - // If there is no currently focused window and no focused application - // then drop the event. - if (mFocusedWindowHandle == NULL) { - if (mFocusedApplicationHandle != NULL) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, NULL, nextWakeupTime, - "Waiting because no window has focus but there is a " - "focused application that may eventually add a window " - "when it finishes starting up."); - goto Unresponsive; - } - - ALOGI("Dropping event because there is no focused window or focused application."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check permissions. - if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - goto Failed; - } - - // If the currently focused window is paused then keep waiting. - if (mFocusedWindowHandle->getInfo()->paused) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, - "Waiting because the focused window is paused."); - goto Unresponsive; - } - - // If the currently focused window is still working on previous events then keep waiting. - if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, - "Waiting because the focused window has not finished " - "processing the input events that were previously delivered to it."); - goto Unresponsive; - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - addWindowTargetLocked(mFocusedWindowHandle, - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), - inputTargets); - - // Done. -Failed: -Unresponsive: - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - ALOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) { - enum InjectionPermission { - INJECTION_PERMISSION_UNKNOWN, - INJECTION_PERMISSION_GRANTED, - INJECTION_PERMISSION_DENIED - }; - - // For security reasons, we defer updating the touch state until we are sure that - // event injection will be allowed. - // - // FIXME In the original code, screenWasOff could never be set to true. - // The reason is that the POLICY_FLAG_WOKE_HERE - // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw - // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was - // actually enqueued using the policyFlags that appeared in the final EV_SYN - // events upon which no preprocessing took place. So policyFlags was always 0. - // In the new native input dispatcher we're a bit more careful about event - // preprocessing so the touches we receive can actually have non-zero policyFlags. - // Unfortunately we obtain undesirable behavior. - // - // Here's what happens: - // - // When the device dims in anticipation of going to sleep, touches - // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause - // the device to brighten and reset the user activity timer. - // Touches on other windows (such as the launcher window) - // are dropped. Then after a moment, the device goes to sleep. Oops. - // - // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE - // instead of POLICY_FLAG_WOKE_HERE... - // - bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE; - - int32_t displayId = entry->displayId; - int32_t action = entry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - - // Update the touch state as needed based on the properties of the touch event. - int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; - InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; - sp<InputWindowHandle> newHoverWindowHandle; - - bool isSplit = mTouchState.split; - bool switchedDevice = mTouchState.deviceId >= 0 && mTouchState.displayId >= 0 - && (mTouchState.deviceId != entry->deviceId - || mTouchState.source != entry->source - || mTouchState.displayId != displayId); - bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); - bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN - || maskedAction == AMOTION_EVENT_ACTION_SCROLL - || isHoverAction); - bool wrongDevice = false; - if (newGesture) { - bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; - if (switchedDevice && mTouchState.down && !down) { -#if DEBUG_FOCUS - ALOGD("Dropping event because a pointer for a different device is already down."); -#endif - mTempTouchState.copyFrom(mTouchState); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - switchedDevice = false; - wrongDevice = true; - goto Failed; - } - mTempTouchState.reset(); - mTempTouchState.down = down; - mTempTouchState.deviceId = entry->deviceId; - mTempTouchState.source = entry->source; - mTempTouchState.displayId = displayId; - isSplit = false; - } else { - mTempTouchState.copyFrom(mTouchState); - } - - if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { - /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ - - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp<InputWindowHandle> newTouchedWindowHandle; - sp<InputWindowHandle> topErrorWindowHandle; - bool isTouchModal = false; - - // Traverse windows from front to back to find touched window and outside targets. - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId != displayId) { - continue; // wrong display - } - - int32_t flags = windowInfo->layoutParamsFlags; - if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) { - if (topErrorWindowHandle == NULL) { - topErrorWindowHandle = windowHandle; - } - } - - if (windowInfo->visible) { - if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - if (! screenWasOff - || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) { - newTouchedWindowHandle = windowHandle; - } - break; // found touched window, exit window loop - } - } - - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; - if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { - outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - mTempTouchState.addOrUpdateWindow( - windowHandle, outsideTargetFlags, BitSet32(0)); - } - } - } - - // If there is an error window but it is not taking focus (typically because - // it is invisible) then wait for it. Any other focused window may in - // fact be in ANR state. - if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, NULL, nextWakeupTime, - "Waiting because a system error window is about to be displayed."); - injectionPermission = INJECTION_PERMISSION_UNKNOWN; - goto Unresponsive; - } - - // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != NULL - && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - // New window supports splitting. - isSplit = true; - } else if (isSplit) { - // New window does not support splitting but we have already split events. - // Ignore the new window. - newTouchedWindowHandle = NULL; - } - - // Handle the case where we did not find a window. - if (newTouchedWindowHandle == NULL) { - // Try to assign the pointer to the first foreground window we find, if there is one. - newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); - if (newTouchedWindowHandle == NULL) { - // There is no touched window. If this is an initial down event - // then wait for a window to appear that will handle the touch. This is - // to ensure that we report an ANR in the case where an application has started - // but not yet put up a window and the user is starting to get impatient. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && mFocusedApplicationHandle != NULL) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, NULL, nextWakeupTime, - "Waiting because there is no touchable window that can " - "handle the event but there is focused application that may " - "eventually add a new window when it finishes starting up."); - goto Unresponsive; - } - - ALOGI("Dropping event because there is no touched window."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - } - - // Set target flags. - int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - // Update hover state. - if (isHoverAction) { - newHoverWindowHandle = newTouchedWindowHandle; - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - newHoverWindowHandle = mLastHoverWindowHandle; - } - - // Update the temporary touch state. - BitSet32 pointerIds; - if (isSplit) { - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - pointerIds.markBit(pointerId); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); - } else { - /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ - - // If the pointer is not currently down, then ignore the event. - if (! mTempTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE - && entry->pointerCount == 1 - && mTempTouchState.isSlippery()) { - int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - - sp<InputWindowHandle> oldTouchedWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - sp<InputWindowHandle> newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y); - if (oldTouchedWindowHandle != newTouchedWindowHandle - && newTouchedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Touch is slipping out of window %s into window %s.", - oldTouchedWindowHandle->getName().string(), - newTouchedWindowHandle->getName().string()); -#endif - // Make a slippery exit from the old window. - mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); - - // Make a slippery entrance into the new window. - if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - isSplit = true; - } - - int32_t targetFlags = InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - BitSet32 pointerIds; - if (isSplit) { - pointerIds.markBit(entry->pointerProperties[0].id); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); - } - } - } - - if (newHoverWindowHandle != mLastHoverWindowHandle) { - // Let the previous window know that the hover sequence is over. - if (mLastHoverWindowHandle != NULL) { -#if DEBUG_HOVER - ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().string()); -#endif - mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); - } - - // Let the new window know that the hover sequence is starting. - if (newHoverWindowHandle != NULL) { -#if DEBUG_HOVER - ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().string()); -#endif - mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); - } - } - - // Check permission to inject into all touched foreground windows and ensure there - // is at least one touched foreground window. - { - bool haveForegroundWindow = false; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.windowHandle, - entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - injectionPermission = INJECTION_PERMISSION_DENIED; - goto Failed; - } - } - } - if (! haveForegroundWindow) { -#if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window to receive it."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Permission granted to injection into all touched foreground windows. - injectionPermission = INJECTION_PERMISSION_GRANTED; - } - - // Check whether windows listening for outside touches are owned by the same UID. If it is - // set the policy flag that we will not reveal coordinate information to this window. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<InputWindowHandle> foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle; - if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { - mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); - } - } - } - } - - // Ensure all touched foreground windows are ready for new input. - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - // If the touched window is paused then keep waiting. - if (touchedWindow.windowHandle->getInfo()->paused) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, - "Waiting because the touched window is paused."); - goto Unresponsive; - } - - // If the touched window is still working on previous events then keep waiting. - if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, - "Waiting because the touched window has not finished " - "processing the input events that were previously delivered to it."); - goto Unresponsive; - } - } - } - - // If this is the first pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper - // engine only supports touch events. We would need to add a mechanism similar - // to View.onGenericMotionEvent to enable wallpapers to handle these events. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp<InputWindowHandle> foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle->getInfo()->hasWallpaper) { - for (size_t i = 0; i < mWindowHandles.size(); i++) { - sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId - && windowHandle->getInfo()->layoutParamsType - == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED - | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); - } - } - } - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); - addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); - } - - // Drop the outside or hover touch windows since we will not care about them - // in the next iteration. - mTempTouchState.filterNonAsIsTouchWindows(); - -Failed: - // Check injection permission once and for all. - if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { - if (checkInjectionPermission(NULL, entry->injectionState)) { - injectionPermission = INJECTION_PERMISSION_GRANTED; - } else { - injectionPermission = INJECTION_PERMISSION_DENIED; - } - } - - // Update final pieces of touch state if the injector had permission. - if (injectionPermission == INJECTION_PERMISSION_GRANTED) { - if (!wrongDevice) { - if (switchedDevice) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Switched to a different device."); -#endif - *outConflictingPointerActions = true; - } - - if (isHoverAction) { - // Started hovering, therefore no longer down. - if (mTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Hover received while pointer was down."); -#endif - *outConflictingPointerActions = true; - } - mTouchState.reset(); - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mTouchState.deviceId = entry->deviceId; - mTouchState.source = entry->source; - mTouchState.displayId = displayId; - } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP - || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { - // All pointers up or canceled. - mTouchState.reset(); - } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - // First pointer went down. - if (mTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Down received while already down."); -#endif - *outConflictingPointerActions = true; - } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - // One pointer went up. - if (isSplit) { - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - - for (size_t i = 0; i < mTempTouchState.windows.size(); ) { - TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); - if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { - touchedWindow.pointerIds.clearBit(pointerId); - if (touchedWindow.pointerIds.isEmpty()) { - mTempTouchState.windows.removeAt(i); - continue; - } - } - i += 1; - } - } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - // Discard temporary touch state since it was only valid for this action. - } else { - // Save changes to touch state as-is for all other actions. - mTouchState.copyFrom(mTempTouchState); - } - - // Update hover state. - mLastHoverWindowHandle = newHoverWindowHandle; - } - } else { -#if DEBUG_FOCUS - ALOGD("Not updating touch focus because injection was denied."); -#endif - } - -Unresponsive: - // Reset temporary touch state to ensure we release unnecessary references to input channels. - mTempTouchState.reset(); - - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) { - inputTargets.push(); - - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - InputTarget& target = inputTargets.editTop(); - target.inputChannel = windowInfo->inputChannel; - target.flags = targetFlags; - target.xOffset = - windowInfo->frameLeft; - target.yOffset = - windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; - target.pointerIds = pointerIds; -} - -void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - inputTargets.push(); - - InputTarget& target = inputTargets.editTop(); - target.inputChannel = mMonitoringChannels[i]; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - target.xOffset = 0; - target.yOffset = 0; - target.pointerIds.clear(); - target.scaleFactor = 1.0f; - } -} - -bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState) { - if (injectionState - && (windowHandle == NULL - || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) - && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { - if (windowHandle != NULL) { - ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " - "owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().string(), - windowHandle->getInfo()->ownerUid); - } else { - ALOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); - } - return false; - } - return true; -} - -bool InputDispatcher::isWindowObscuredAtPointLocked( - const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const { - int32_t displayId = windowHandle->getInfo()->displayId; - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp<InputWindowHandle> otherHandle = mWindowHandles.itemAt(i); - if (otherHandle == windowHandle) { - break; - } - - const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->frameContainsPoint(x, y)) { - return true; - } - } - return false; -} - -bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry) { - ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - if (connection->inputPublisherBlocked) { - return false; - } - if (eventEntry->type == EventEntry::TYPE_KEY) { - // If the event is a key event, then we must wait for all previous events to - // complete before delivering it because previous events may have the - // side-effect of transferring focus to a different window and we want to - // ensure that the following keys are sent to the new window. - // - // Suppose the user touches a button in a window then immediately presses "A". - // If the button causes a pop-up window to appear then we want to ensure that - // the "A" key is delivered to the new pop-up window. This is because users - // often anticipate pending UI changes when typing on a keyboard. - // To obtain this behavior, we must serialize key events with respect to all - // prior input events. - return connection->outboundQueue.isEmpty() - && connection->waitQueue.isEmpty(); - } - // Touch events can always be sent to a window immediately because the user intended - // to touch whatever was visible at the time. Even if focus changes or a new - // window appears moments later, the touch event was meant to be delivered to - // whatever window happened to be on screen at the time. - // - // Generic motion events, such as trackball or joystick events are a little trickier. - // Like key events, generic motion events are delivered to the focused window. - // Unlike key events, generic motion events don't tend to transfer focus to other - // windows and it is not important for them to be serialized. So we prefer to deliver - // generic motion events as soon as possible to improve efficiency and reduce lag - // through batching. - // - // The one case where we pause input event delivery is when the wait queue is piling - // up with lots of events because the application is not responding. - // This condition ensures that ANRs are detected reliably. - if (!connection->waitQueue.isEmpty() - && currentTime >= connection->waitQueue.head->eventEntry->eventTime - + STREAM_AHEAD_EVENT_TIMEOUT) { - return false; - } - } - return true; -} - -String8 InputDispatcher::getApplicationWindowLabelLocked( - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle) { - if (applicationHandle != NULL) { - if (windowHandle != NULL) { - String8 label(applicationHandle->getName()); - label.append(" - "); - label.append(windowHandle->getName()); - return label; - } else { - return applicationHandle->getName(); - } - } else if (windowHandle != NULL) { - return windowHandle->getName(); - } else { - return String8("<unknown application or window>"); - } -} - -void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { - if (mFocusedWindowHandle != NULL) { - const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); - if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string()); -#endif - return; - } - } - - int32_t eventType = USER_ACTIVITY_EVENT_OTHER; - switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } - - if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; - } - break; - } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; - } - eventType = USER_ACTIVITY_EVENT_BUTTON; - break; - } - } - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doPokeUserActivityLockedInterruptible); - commandEntry->eventTime = eventEntry->eventTime; - commandEntry->userActivityEventType = eventType; -} - -void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, scaleFactor=%f, " - "pointerIds=0x%x", - connection->getInputChannelName(), inputTarget->flags, - inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor, inputTarget->pointerIds.value); -#endif - - // Skip this event if the connection status is not normal. - // We don't want to enqueue additional outbound events if the connection is broken. - if (connection->status != Connection::STATUS_NORMAL) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName(), connection->getStatusLabel()); -#endif - return; - } - - // Split a motion event if needed. - if (inputTarget->flags & InputTarget::FLAG_SPLIT) { - ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION); - - MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry); - if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = splitMotionEvent( - originalMotionEntry, inputTarget->pointerIds); - if (!splitMotionEntry) { - return; // split event was dropped - } -#if DEBUG_FOCUS - ALOGD("channel '%s' ~ Split motion event.", - connection->getInputChannelName()); - logOutboundMotionDetailsLocked(" ", splitMotionEntry); -#endif - enqueueDispatchEntriesLocked(currentTime, connection, - splitMotionEntry, inputTarget); - splitMotionEntry->release(); - return; - } - } - - // Not splitting. Enqueue dispatch entries for the event as is. - enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); -} - -void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { - bool wasEmpty = connection->outboundQueue.isEmpty(); - - // Enqueue dispatch entries for the requested modes. - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_IS); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); - - // If the outbound queue was previously empty, start the dispatch cycle going. - if (wasEmpty && !connection->outboundQueue.isEmpty()) { - startDispatchCycleLocked(currentTime, connection); - } -} - -void InputDispatcher::enqueueDispatchEntryLocked( - const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, - int32_t dispatchMode) { - int32_t inputTargetFlags = inputTarget->flags; - if (!(inputTargetFlags & dispatchMode)) { - return; - } - inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; - - // This is a new event. - // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref - inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor); - - // Apply target flags and update the connection's input state. - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - dispatchEntry->resolvedAction = keyEntry->action; - dispatchEntry->resolvedFlags = keyEntry->flags; - - if (!connection->inputState.trackKey(keyEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", - connection->getInputChannelName()); -#endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; - } else { - dispatchEntry->resolvedAction = motionEntry->action; - } - if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - && !connection->inputState.isHovering( - motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", - connection->getInputChannelName()); -#endif - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } - - dispatchEntry->resolvedFlags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - - if (!connection->inputState.trackMotion(motionEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", - connection->getInputChannelName()); -#endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - } - - // Remember that we are waiting for this dispatch to complete. - if (dispatchEntry->hasForegroundTarget()) { - incrementPendingForegroundDispatchesLocked(eventEntry); - } - - // Enqueue the dispatch entry. - connection->outboundQueue.enqueueAtTail(dispatchEntry); - traceOutboundQueueLengthLocked(connection); -} - -void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ startDispatchCycle", - connection->getInputChannelName()); -#endif - - while (connection->status == Connection::STATUS_NORMAL - && !connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.head; - dispatchEntry->deliveryTime = currentTime; - - // Publish the event. - status_t status; - EventEntry* eventEntry = dispatchEntry->eventEntry; - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry); - - // Publish the key event. - status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, - keyEntry->deviceId, keyEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - keyEntry->keyCode, keyEntry->scanCode, - keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry); - - PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry->pointerCoords; - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset, scaleFactor; - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - scaleFactor = dispatchEntry->scaleFactor; - xOffset = dispatchEntry->xOffset * scaleFactor; - yOffset = dispatchEntry->yOffset * scaleFactor; - if (scaleFactor != 1.0f) { - for (size_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(scaleFactor); - } - usingCoords = scaledCoords; - } - } else { - xOffset = 0.0f; - yOffset = 0.0f; - scaleFactor = 1.0f; - - // We don't want the dispatch target to know. - if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { - for (size_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i].clear(); - } - usingCoords = scaledCoords; - } - } - - // Publish the motion event. - status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, - xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, motionEntry->eventTime, - motionEntry->pointerCount, motionEntry->pointerProperties, - usingCoords); - break; - } - - default: - ALOG_ASSERT(false); - return; - } - - // Check the result. - if (status) { - if (status == WOULD_BLOCK) { - if (connection->waitQueue.isEmpty()) { - ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " - "This is unexpected because the wait queue is empty, so the pipe " - "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - } else { - // Pipe is full and we are waiting for the app to finish process some events - // before sending more events to it. -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " - "waiting for the application to catch up", - connection->getInputChannelName()); -#endif - connection->inputPublisherBlocked = true; - } - } else { - ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - } - return; - } - - // Re-enqueue the event on the wait queue. - connection->outboundQueue.dequeue(dispatchEntry); - traceOutboundQueueLengthLocked(connection); - connection->waitQueue.enqueueAtTail(dispatchEntry); - traceWaitQueueLengthLocked(connection); - } -} - -void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, uint32_t seq, bool handled) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", - connection->getInputChannelName(), seq, toString(handled)); -#endif - - connection->inputPublisherBlocked = false; - - if (connection->status == Connection::STATUS_BROKEN - || connection->status == Connection::STATUS_ZOMBIE) { - return; - } - - // Notify other system components and prepare to start the next dispatch cycle. - onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); -} - -void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp<Connection>& connection, bool notify) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", - connection->getInputChannelName(), toString(notify)); -#endif - - // Clear the dispatch queues. - drainDispatchQueueLocked(&connection->outboundQueue); - traceOutboundQueueLengthLocked(connection); - drainDispatchQueueLocked(&connection->waitQueue); - traceWaitQueueLengthLocked(connection); - - // The connection appears to be unrecoverably broken. - // Ignore already broken or zombie connections. - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; - - if (notify) { - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); - } - } -} - -void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) { - while (!queue->isEmpty()) { - DispatchEntry* dispatchEntry = queue->dequeueAtHead(); - releaseDispatchEntryLocked(dispatchEntry); - } -} - -void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) { - if (dispatchEntry->hasForegroundTarget()) { - decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); - } - delete dispatchEntry; -} - -int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { - InputDispatcher* d = static_cast<InputDispatcher*>(data); - - { // acquire lock - AutoMutex _l(d->mLock); - - ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); - if (connectionIndex < 0) { - ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", fd, events); - return 0; // remove the callback - } - - bool notify; - sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex); - if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { - if (!(events & ALOOPER_EVENT_INPUT)) { - ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", connection->getInputChannelName(), events); - return 1; - } - - nsecs_t currentTime = now(); - bool gotOne = false; - status_t status; - for (;;) { - uint32_t seq; - bool handled; - status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); - if (status) { - break; - } - d->finishDispatchCycleLocked(currentTime, connection, seq, handled); - gotOne = true; - } - if (gotOne) { - d->runCommandsLockedInterruptible(); - if (status == WOULD_BLOCK) { - return 1; - } - } - - notify = status != DEAD_OBJECT || !connection->monitor; - if (notify) { - ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName(), status); - } - } else { - // Monitor channels are never explicitly unregistered. - // We do it automatically when the remote endpoint is closed so don't warn - // about them. - notify = !connection->monitor; - if (notify) { - ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", connection->getInputChannelName(), events); - } - } - - // Unregister the channel. - d->unregisterInputChannelLocked(connection->inputChannel, notify); - return 0; // remove the callback - } // release lock -} - -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options) { - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(i), options); - } -} - -void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( - const sp<InputChannel>& channel, const CancelationOptions& options) { - ssize_t index = getConnectionIndexLocked(channel); - if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(index), options); - } -} - -void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( - const sp<Connection>& connection, const CancelationOptions& options) { - if (connection->status == Connection::STATUS_BROKEN) { - return; - } - - nsecs_t currentTime = now(); - - Vector<EventEntry*> cancelationEvents; - connection->inputState.synthesizeCancelationEvents(currentTime, - cancelationEvents, options); - - if (!cancelationEvents.isEmpty()) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " - "with reality: %s, mode=%d.", - connection->getInputChannelName(), cancelationEvents.size(), - options.reason, options.mode); -#endif - for (size_t i = 0; i < cancelationEvents.size(); i++) { - EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i); - switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetailsLocked("cancel - ", - static_cast<KeyEntry*>(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetailsLocked("cancel - ", - static_cast<MotionEntry*>(cancelationEventEntry)); - break; - } - - InputTarget target; - sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel); - if (windowHandle != NULL) { - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - target.xOffset = -windowInfo->frameLeft; - target.yOffset = -windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; - } else { - target.xOffset = 0; - target.yOffset = 0; - target.scaleFactor = 1.0f; - } - target.inputChannel = connection->inputChannel; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - - enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref - &target, InputTarget::FLAG_DISPATCH_AS_IS); - - cancelationEventEntry->release(); - } - - startDispatchCycleLocked(currentTime, connection); - } -} - -InputDispatcher::MotionEntry* -InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { - ALOG_ASSERT(pointerIds.value != 0); - - PointerProperties splitPointerProperties[MAX_POINTERS]; - PointerCoords splitPointerCoords[MAX_POINTERS]; - - uint32_t originalPointerCount = originalMotionEntry->pointerCount; - uint32_t splitPointerCount = 0; - - for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { - const PointerProperties& pointerProperties = - originalMotionEntry->pointerProperties[originalPointerIndex]; - uint32_t pointerId = uint32_t(pointerProperties.id); - if (pointerIds.hasBit(pointerId)) { - splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); - splitPointerCoords[splitPointerCount].copyFrom( - originalMotionEntry->pointerCoords[originalPointerIndex]); - splitPointerCount += 1; - } - } - - if (splitPointerCount != pointerIds.count()) { - // This is bad. We are missing some of the pointers that we expected to deliver. - // Most likely this indicates that we received an ACTION_MOVE events that has - // different pointer ids than we expected based on the previous ACTION_DOWN - // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers - // in this way. - ALOGW("Dropping split motion event because the pointer count is %d but " - "we expected there to be %d pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); - return NULL; - } - - int32_t action = originalMotionEntry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); - const PointerProperties& pointerProperties = - originalMotionEntry->pointerProperties[originalPointerIndex]; - uint32_t pointerId = uint32_t(pointerProperties.id); - if (pointerIds.hasBit(pointerId)) { - if (pointerIds.count() == 1) { - // The first/last pointer went down/up. - action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else { - // A secondary pointer went down/up. - uint32_t splitPointerIndex = 0; - while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { - splitPointerIndex += 1; - } - action = maskedAction | (splitPointerIndex - << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - } - } else { - // An unrelated pointer changed. - action = AMOTION_EVENT_ACTION_MOVE; - } - } - - MotionEntry* splitMotionEntry = new MotionEntry( - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->buttonState, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - originalMotionEntry->displayId, - splitPointerCount, splitPointerProperties, splitPointerCoords); - - if (originalMotionEntry->injectionState) { - splitMotionEntry->injectionState = originalMotionEntry->injectionState; - splitMotionEntry->injectionState->refCount += 1; - } - - return splitMotionEntry; -} - -void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", - args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->keyCode, args->scanCode, - args->metaState, args->downTime); -#endif - if (!validateKeyEvent(args->action)) { - return; - } - - uint32_t policyFlags = args->policyFlags; - int32_t flags = args->flags; - int32_t metaState = args->metaState; - if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { - policyFlags |= POLICY_FLAG_VIRTUAL; - flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - } - if (policyFlags & POLICY_FLAG_ALT) { - metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON; - } - if (policyFlags & POLICY_FLAG_ALT_GR) { - metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON; - } - if (policyFlags & POLICY_FLAG_SHIFT) { - metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON; - } - if (policyFlags & POLICY_FLAG_CAPS_LOCK) { - metaState |= AMETA_CAPS_LOCK_ON; - } - if (policyFlags & POLICY_FLAG_FUNCTION) { - metaState |= AMETA_FUNCTION_ON; - } - - policyFlags |= POLICY_FLAG_TRUSTED; - - KeyEvent event; - event.initialize(args->deviceId, args->source, args->action, - flags, args->keyCode, args->scanCode, metaState, 0, - args->downTime, args->eventTime); - - mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - bool needWake; - { // acquire lock - mLock.lock(); - - if (shouldSendKeyToInputFilterLocked(args)) { - mLock.unlock(); - - policyFlags |= POLICY_FLAG_FILTERED; - if (!mPolicy->filterInputEvent(&event, policyFlags)) { - return; // event was consumed by the filter - } - - mLock.lock(); - } - - int32_t repeatCount = 0; - KeyEntry* newEntry = new KeyEntry(args->eventTime, - args->deviceId, args->source, policyFlags, - args->action, flags, args->keyCode, args->scanCode, - metaState, repeatCount, args->downTime); - - needWake = enqueueInboundEventLocked(newEntry); - mLock.unlock(); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) { - return mInputFilterEnabled; -} - -void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " - "xPrecision=%f, yPrecision=%f, downTime=%lld", - args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); - for (uint32_t i = 0; i < args->pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, args->pointerProperties[i].id, - args->pointerProperties[i].toolType, - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } -#endif - if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { - return; - } - - uint32_t policyFlags = args->policyFlags; - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); - - bool needWake; - { // acquire lock - mLock.lock(); - - if (shouldSendMotionToInputFilterLocked(args)) { - mLock.unlock(); - - MotionEvent event; - event.initialize(args->deviceId, args->source, args->action, args->flags, - args->edgeFlags, args->metaState, args->buttonState, 0, 0, - args->xPrecision, args->yPrecision, - args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); - - policyFlags |= POLICY_FLAG_FILTERED; - if (!mPolicy->filterInputEvent(&event, policyFlags)) { - return; // event was consumed by the filter - } - - mLock.lock(); - } - - // Just enqueue a new motion event. - MotionEntry* newEntry = new MotionEntry(args->eventTime, - args->deviceId, args->source, policyFlags, - args->action, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, - args->displayId, - args->pointerCount, args->pointerProperties, args->pointerCoords); - - needWake = enqueueInboundEventLocked(newEntry); - mLock.unlock(); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) { - // TODO: support sending secondary display events to input filter - return mInputFilterEnabled && isMainDisplay(args->displayId); -} - -void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x", - args->eventTime, args->policyFlags, - args->switchValues, args->switchMask); -#endif - - uint32_t policyFlags = args->policyFlags; - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, - args->switchValues, args->switchMask, policyFlags); -} - -void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", - args->eventTime, args->deviceId); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); -#endif - - nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); - - policyFlags |= POLICY_FLAG_INJECTED; - if (hasInjectionPermission(injectorPid, injectorUid)) { - policyFlags |= POLICY_FLAG_TRUSTED; - } - - EventEntry* firstInjectedEntry; - EventEntry* lastInjectedEntry; - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event); - int32_t action = keyEvent->getAction(); - if (! validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - int32_t flags = keyEvent->getFlags(); - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; - } - - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); - } - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - mLock.lock(); - firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(), - keyEvent->getDeviceId(), keyEvent->getSource(), - policyFlags, action, flags, - keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), keyEvent->getDownTime()); - lastInjectedEntry = firstInjectedEntry; - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast<const MotionEvent*>(event); - int32_t displayId = ADISPLAY_ID_DEFAULT; - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - if (! validateMotionEvent(action, pointerCount, pointerProperties)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - nsecs_t eventTime = motionEvent->getEventTime(); - mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); - } - - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = new MotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); - lastInjectedEntry = firstInjectedEntry; - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); - lastInjectedEntry->next = nextInjectedEntry; - lastInjectedEntry = nextInjectedEntry; - } - break; - } - - default: - ALOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; - } - - InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionState->injectionIsAsync = true; - } - - injectionState->refCount += 1; - lastInjectedEntry->injectionState = injectionState; - - bool needWake = false; - for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) { - EventEntry* nextEntry = entry->next; - needWake |= enqueueInboundEventLocked(entry); - entry = nextEntry; - } - - mLock.unlock(); - - if (needWake) { - mLooper->wake(); - } - - int32_t injectionResult; - { // acquire lock - AutoMutex _l(mLock); - - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - } else { - for (;;) { - injectionResult = injectionState->injectionResult; - if (injectionResult != INPUT_EVENT_INJECTION_PENDING) { - break; - } - - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout); - } - - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED - && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { - while (injectionState->pendingForegroundDispatches != 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); -#endif - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout); - } - } - } - - injectionState->release(); - } // release lock - -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); -#endif - - return injectionResult; -} - -bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); -} - -void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { -#if DEBUG_INJECTION - ALOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); -#endif - - if (injectionState->injectionIsAsync - && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { - // Log the outcome since the injector did not wait for the injection result. - switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - ALOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - ALOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - ALOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - ALOGW("Asynchronous input event injection timed out."); - break; - } - } - - injectionState->injectionResult = injectionResult; - mInjectionResultAvailableCondition.broadcast(); - } -} - -void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches += 1; - } -} - -void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches -= 1; - - if (injectionState->pendingForegroundDispatches == 0) { - mInjectionSyncFinishedCondition.broadcast(); - } - } -} - -sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked( - const sp<InputChannel>& inputChannel) const { - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); - if (windowHandle->getInputChannel() == inputChannel) { - return windowHandle; - } - } - return NULL; -} - -bool InputDispatcher::hasWindowHandleLocked( - const sp<InputWindowHandle>& windowHandle) const { - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - if (mWindowHandles.itemAt(i) == windowHandle) { - return true; - } - } - return false; -} - -void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) { -#if DEBUG_FOCUS - ALOGD("setInputWindows"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - Vector<sp<InputWindowHandle> > oldWindowHandles = mWindowHandles; - mWindowHandles = inputWindowHandles; - - sp<InputWindowHandle> newFocusedWindowHandle; - bool foundHoveredWindow = false; - for (size_t i = 0; i < mWindowHandles.size(); i++) { - const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); - if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) { - mWindowHandles.removeAt(i--); - continue; - } - if (windowHandle->getInfo()->hasFocus) { - newFocusedWindowHandle = windowHandle; - } - if (windowHandle == mLastHoverWindowHandle) { - foundHoveredWindow = true; - } - } - - if (!foundHoveredWindow) { - mLastHoverWindowHandle = NULL; - } - - if (mFocusedWindowHandle != newFocusedWindowHandle) { - if (mFocusedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Focus left window: %s", - mFocusedWindowHandle->getName().string()); -#endif - sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel(); - if (focusedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked( - focusedInputChannel, options); - } - } - if (newFocusedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Focus entered window: %s", - newFocusedWindowHandle->getName().string()); -#endif - } - mFocusedWindowHandle = newFocusedWindowHandle; - } - - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); - if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { -#if DEBUG_FOCUS - ALOGD("Touched window was removed: %s", - touchedWindow.windowHandle->getName().string()); -#endif - sp<InputChannel> touchedInputChannel = - touchedWindow.windowHandle->getInputChannel(); - if (touchedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked( - touchedInputChannel, options); - } - mTouchState.windows.removeAt(i--); - } - } - - // Release information for windows that are no longer present. - // This ensures that unused input channels are released promptly. - // Otherwise, they might stick around until the window handle is destroyed - // which might not happen until the next GC. - for (size_t i = 0; i < oldWindowHandles.size(); i++) { - const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i); - if (!hasWindowHandleLocked(oldWindowHandle)) { -#if DEBUG_FOCUS - ALOGD("Window went away: %s", oldWindowHandle->getName().string()); -#endif - oldWindowHandle->releaseInfo(); - } - } - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setFocusedApplication( - const sp<InputApplicationHandle>& inputApplicationHandle) { -#if DEBUG_FOCUS - ALOGD("setFocusedApplication"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) { - if (mFocusedApplicationHandle != inputApplicationHandle) { - if (mFocusedApplicationHandle != NULL) { - resetANRTimeoutsLocked(); - mFocusedApplicationHandle->releaseInfo(); - } - mFocusedApplicationHandle = inputApplicationHandle; - } - } else if (mFocusedApplicationHandle != NULL) { - resetANRTimeoutsLocked(); - mFocusedApplicationHandle->releaseInfo(); - mFocusedApplicationHandle.clear(); - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { -#if DEBUG_FOCUS - ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); -#endif - - bool changed; - { // acquire lock - AutoMutex _l(mLock); - - if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { - if (mDispatchFrozen && !frozen) { - resetANRTimeoutsLocked(); - } - - if (mDispatchEnabled && !enabled) { - resetAndDropEverythingLocked("dispatcher is being disabled"); - } - - mDispatchEnabled = enabled; - mDispatchFrozen = frozen; - changed = true; - } else { - changed = false; - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - if (changed) { - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - } -} - -void InputDispatcher::setInputFilterEnabled(bool enabled) { -#if DEBUG_FOCUS - ALOGD("setInputFilterEnabled: enabled=%d", enabled); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (mInputFilterEnabled == enabled) { - return; - } - - mInputFilterEnabled = enabled; - resetAndDropEverythingLocked("input filter is being enabled or disabled"); - } // release lock - - // Wake up poll loop since there might be work to do to drop everything. - mLooper->wake(); -} - -bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) { -#if DEBUG_FOCUS - ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", - fromChannel->getName().string(), toChannel->getName().string()); -#endif - { // acquire lock - AutoMutex _l(mLock); - - sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel); - sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel); - if (fromWindowHandle == NULL || toWindowHandle == NULL) { -#if DEBUG_FOCUS - ALOGD("Cannot transfer focus because from or to window not found."); -#endif - return false; - } - if (fromWindowHandle == toWindowHandle) { -#if DEBUG_FOCUS - ALOGD("Trivial transfer to same window."); -#endif - return true; - } - if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { -#if DEBUG_FOCUS - ALOGD("Cannot transfer focus because windows are on different displays."); -#endif - return false; - } - - bool found = false; - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - if (touchedWindow.windowHandle == fromWindowHandle) { - int32_t oldTargetFlags = touchedWindow.targetFlags; - BitSet32 pointerIds = touchedWindow.pointerIds; - - mTouchState.windows.removeAt(i); - - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); - mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); - - found = true; - break; - } - } - - if (! found) { -#if DEBUG_FOCUS - ALOGD("Focus transfer failed because from window did not have focus."); -#endif - return false; - } - - ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); - ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); - if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { - sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); - sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex); - - fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); - synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - } - -#if DEBUG_FOCUS - logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - return true; -} - -void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { -#if DEBUG_FOCUS - ALOGD("Resetting and dropping all events (%s).", reason); -#endif - - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - resetANRTimeoutsLocked(); - - mTouchState.reset(); - mLastHoverWindowHandle.clear(); -} - -void InputDispatcher::logDispatchStateLocked() { - String8 dump; - dumpDispatchStateLocked(dump); - - char* text = dump.lockBuffer(dump.size()); - char* start = text; - while (*start != '\0') { - char* end = strchr(start, '\n'); - if (*end == '\n') { - *(end++) = '\0'; - } - ALOGD("%s", start); - start = end; - } -} - -void InputDispatcher::dumpDispatchStateLocked(String8& dump) { - dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); - dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); - - if (mFocusedApplicationHandle != NULL) { - dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", - mFocusedApplicationHandle->getName().string(), - mFocusedApplicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); - } else { - dump.append(INDENT "FocusedApplication: <null>\n"); - } - dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", - mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>"); - - dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); - dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); - dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId); - dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source); - dump.appendFormat(INDENT "TouchDisplayId: %d\n", mTouchState.displayId); - if (!mTouchState.windows.isEmpty()) { - dump.append(INDENT "TouchedWindows:\n"); - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().string(), - touchedWindow.pointerIds.value, - touchedWindow.targetFlags); - } - } else { - dump.append(INDENT "TouchedWindows: <none>\n"); - } - - if (!mWindowHandles.isEmpty()) { - dump.append(INDENT "Windows:\n"); - for (size_t i = 0; i < mWindowHandles.size(); i++) { - const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - - dump.appendFormat(INDENT2 "%d: name='%s', displayId=%d, " - "paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], scale=%f, " - "touchableRegion=", - i, windowInfo->name.string(), windowInfo->displayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, - windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->scaleFactor); - dumpRegion(dump, windowInfo->touchableRegion); - dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures); - dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); - } - } else { - dump.append(INDENT "Windows: <none>\n"); - } - - if (!mMonitoringChannels.isEmpty()) { - dump.append(INDENT "MonitoringChannels:\n"); - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - const sp<InputChannel>& channel = mMonitoringChannels[i]; - dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string()); - } - } else { - dump.append(INDENT "MonitoringChannels: <none>\n"); - } - - nsecs_t currentTime = now(); - - if (!mInboundQueue.isEmpty()) { - dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); - for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { - dump.append(INDENT2); - entry->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT "InboundQueue: <empty>\n"); - } - - if (!mConnectionsByFd.isEmpty()) { - dump.append(INDENT "Connections:\n"); - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - const sp<Connection>& connection = mConnectionsByFd.valueAt(i); - dump.appendFormat(INDENT2 "%d: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", - i, connection->getInputChannelName(), connection->getWindowName(), - connection->getStatusLabel(), toString(connection->monitor), - toString(connection->inputPublisherBlocked)); - - if (!connection->outboundQueue.isEmpty()) { - dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n", - connection->outboundQueue.count()); - for (DispatchEntry* entry = connection->outboundQueue.head; entry; - entry = entry->next) { - dump.append(INDENT4); - entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT3 "OutboundQueue: <empty>\n"); - } - - if (!connection->waitQueue.isEmpty()) { - dump.appendFormat(INDENT3 "WaitQueue: length=%u\n", - connection->waitQueue.count()); - for (DispatchEntry* entry = connection->waitQueue.head; entry; - entry = entry->next) { - dump.append(INDENT4); - entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, " - "age=%0.1fms, wait=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f, - (currentTime - entry->deliveryTime) * 0.000001f); - } - } else { - dump.append(INDENT3 "WaitQueue: <empty>\n"); - } - } - } else { - dump.append(INDENT "Connections: <none>\n"); - } - - if (isAppSwitchPendingLocked()) { - dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); - } else { - dump.append(INDENT "AppSwitch: not pending\n"); - } - - dump.append(INDENT "Configuration:\n"); - dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", - mConfig.keyRepeatDelay * 0.000001f); - dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", - mConfig.keyRepeatTimeout * 0.000001f); -} - -status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) { -#if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), - toString(monitor)); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (getConnectionIndexLocked(inputChannel) >= 0) { - ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor); - - int fd = inputChannel->getFd(); - mConnectionsByFd.add(fd, connection); - - if (monitor) { - mMonitoringChannels.push(inputChannel); - } - - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - } // release lock - - // Wake the looper because some connections have changed. - mLooper->wake(); - return OK; -} - -status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) { -#if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string()); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/); - if (status) { - return status; - } - } // release lock - - // Wake the poll loop because removing the connection may have changed the current - // synchronization state. - mLooper->wake(); - return OK; -} - -status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, - bool notify) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex < 0) { - ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - mConnectionsByFd.removeItemsAt(connectionIndex); - - if (connection->monitor) { - removeMonitorChannelLocked(inputChannel); - } - - mLooper->removeFd(inputChannel->getFd()); - - nsecs_t currentTime = now(); - abortBrokenDispatchCycleLocked(currentTime, connection, notify); - - connection->status = Connection::STATUS_ZOMBIE; - return OK; -} - -void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputChannel) { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - if (mMonitoringChannels[i] == inputChannel) { - mMonitoringChannels.removeAt(i); - break; - } - } -} - -ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) { - ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); - if (connectionIndex >= 0) { - sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex); - if (connection->inputChannel.get() == inputChannel.get()) { - return connectionIndex; - } - } - - return -1; -} - -void InputDispatcher::onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); - commandEntry->connection = connection; - commandEntry->eventTime = currentTime; - commandEntry->seq = seq; - commandEntry->handled = handled; -} - -void InputDispatcher::onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection) { - ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName()); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); - commandEntry->connection = connection; -} - -void InputDispatcher::onANRLocked( - nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { - float dispatchLatency = (currentTime - eventTime) * 0.000001f; - float waitDuration = (currentTime - waitStartTime) * 0.000001f; - ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), - dispatchLatency, waitDuration, reason); - - // Capture a record of the InputDispatcher state at the time of the ANR. - time_t t = time(NULL); - struct tm tm; - localtime_r(&t, &tm); - char timestr[64]; - strftime(timestr, sizeof(timestr), "%F %T", &tm); - mLastANRState.clear(); - mLastANRState.append(INDENT "ANR:\n"); - mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr); - mLastANRState.appendFormat(INDENT2 "Window: %s\n", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string()); - mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); - mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); - mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason); - dumpDispatchStateLocked(mLastANRState); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyANRLockedInterruptible); - commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputWindowHandle = windowHandle; -} - -void InputDispatcher::doNotifyConfigurationChangedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->notifyConfigurationChanged(commandEntry->eventTime); - - mLock.lock(); -} - -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( - CommandEntry* commandEntry) { - sp<Connection> connection = commandEntry->connection; - - if (connection->status != Connection::STATUS_ZOMBIE) { - mLock.unlock(); - - mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); - - mLock.lock(); - } -} - -void InputDispatcher::doNotifyANRLockedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle); - - mLock.lock(); - - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, - commandEntry->inputWindowHandle != NULL - ? commandEntry->inputWindowHandle->getInputChannel() : NULL); -} - -void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( - CommandEntry* commandEntry) { - KeyEntry* entry = commandEntry->keyEntry; - - KeyEvent event; - initializeKeyEvent(&event, entry); - - mLock.unlock(); - - nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, - &event, entry->policyFlags); - - mLock.lock(); - - if (delay < 0) { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; - } else if (!delay) { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; - entry->interceptKeyWakeupTime = now() + delay; - } - entry->release(); -} - -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( - CommandEntry* commandEntry) { - sp<Connection> connection = commandEntry->connection; - nsecs_t finishTime = commandEntry->eventTime; - uint32_t seq = commandEntry->seq; - bool handled = commandEntry->handled; - - // Handle post-event policy actions. - DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq); - if (dispatchEntry) { - nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; - if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { - String8 msg; - msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", - connection->getWindowName(), eventDuration * 0.000001f); - dispatchEntry->eventEntry->appendDescription(msg); - ALOGI("%s", msg.string()); - } - - bool restartEvent; - if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { - KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry); - restartEvent = afterKeyEventLockedInterruptible(connection, - dispatchEntry, keyEntry, handled); - } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { - MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry); - restartEvent = afterMotionEventLockedInterruptible(connection, - dispatchEntry, motionEntry, handled); - } else { - restartEvent = false; - } - - // Dequeue the event and start the next cycle. - // Note that because the lock might have been released, it is possible that the - // contents of the wait queue to have been drained, so we need to double-check - // a few things. - if (dispatchEntry == connection->findWaitQueueEntry(seq)) { - connection->waitQueue.dequeue(dispatchEntry); - traceWaitQueueLengthLocked(connection); - if (restartEvent && connection->status == Connection::STATUS_NORMAL) { - connection->outboundQueue.enqueueAtHead(dispatchEntry); - traceOutboundQueueLengthLocked(connection); - } else { - releaseDispatchEntryLocked(dispatchEntry); - } - } - - // Start the next dispatch cycle for this connection. - startDispatchCycleLocked(now(), connection); - } -} - -bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { - if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { - // Get the fallback key state. - // Clear it out after dispatching the UP. - int32_t originalKeyCode = keyEntry->keyCode; - int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); - if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - connection->inputState.removeFallbackKey(originalKeyCode); - } - - if (handled || !dispatchEntry->hasForegroundTarget()) { - // If the application handles the original key for which we previously - // generated a fallback or if the window is not a foreground window, - // then cancel the associated fallback key, if any. - if (fallbackKeyCode != -1) { - // Dispatch the unhandled key to the policy with the cancel flag. -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Asking policy to cancel fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); - - mLock.unlock(); - - mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - // Cancel the fallback key. - if (fallbackKeyCode != AKEYCODE_UNKNOWN) { - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "application handled the original non-fallback key " - "or is no longer a foreground target, " - "canceling previously dispatched fallback key"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - connection->inputState.removeFallbackKey(originalKeyCode); - } - } else { - // If the application did not handle a non-fallback key, first check - // that we are in a good state to perform unhandled key event processing - // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN - && keyEntry->repeatCount == 0; - if (fallbackKeyCode == -1 && !initialDown) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - originalKeyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - return false; - } - - // Dispatch the unhandled key to the policy. -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - - mLock.unlock(); - - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - if (connection->status != Connection::STATUS_NORMAL) { - connection->inputState.removeFallbackKey(originalKeyCode); - return false; - } - - // Latch the fallback keycode for this key on an initial down. - // The fallback keycode cannot change at any other point in the lifecycle. - if (initialDown) { - if (fallback) { - fallbackKeyCode = event.getKeyCode(); - } else { - fallbackKeyCode = AKEYCODE_UNKNOWN; - } - connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); - } - - ALOG_ASSERT(fallbackKeyCode != -1); - - // Cancel the fallback key if the policy decides not to send it anymore. - // We will continue to dispatch the key to the policy but we will no - // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN - && (!fallback || fallbackKeyCode != event.getKeyCode())) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - if (fallback) { - ALOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); - } else { - ALOGD("Unhandled key event: Policy did not request fallback for %d, " - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); - } -#endif - - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "canceling fallback, policy no longer desires it"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - - fallback = false; - fallbackKeyCode = AKEYCODE_UNKNOWN; - if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, - fallbackKeyCode); - } - } - -#if DEBUG_OUTBOUND_EVENT_DETAILS - { - String8 msg; - const KeyedVector<int32_t, int32_t>& fallbackKeys = - connection->inputState.getFallbackKeys(); - for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), - fallbackKeys.valueAt(i)); - } - ALOGD("Unhandled key event: %d currently tracked fallback keys%s.", - fallbackKeys.size(), msg.string()); - } -#endif - - if (fallback) { - // Restart the dispatch cycle using the fallback key. - keyEntry->eventTime = event.getEventTime(); - keyEntry->deviceId = event.getDeviceId(); - keyEntry->source = event.getSource(); - keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; - keyEntry->keyCode = fallbackKeyCode; - keyEntry->scanCode = event.getScanCode(); - keyEntry->metaState = event.getMetaState(); - keyEntry->repeatCount = event.getRepeatCount(); - keyEntry->downTime = event.getDownTime(); - keyEntry->syntheticRepeat = false; - -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); -#endif - return true; // restart the event - } else { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: No fallback key."); -#endif - } - } - } - return false; -} - -bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { - return false; -} - -void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType); - - mLock.lock(); -} - -void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { - event->initialize(entry->deviceId, entry->source, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); -} - -void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { - // TODO Write some statistics about how long we spend waiting. -} - -void InputDispatcher::traceInboundQueueLengthLocked() { -#ifdef HAVE_ANDROID_OS - if (ATRACE_ENABLED()) { - ATRACE_INT("iq", mInboundQueue.count()); - } -#endif -} - -void InputDispatcher::traceOutboundQueueLengthLocked(const sp<Connection>& connection) { -#ifdef HAVE_ANDROID_OS - if (ATRACE_ENABLED()) { - char counterName[40]; - snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName()); - ATRACE_INT(counterName, connection->outboundQueue.count()); - } -#endif -} - -void InputDispatcher::traceWaitQueueLengthLocked(const sp<Connection>& connection) { -#ifdef HAVE_ANDROID_OS - if (ATRACE_ENABLED()) { - char counterName[40]; - snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName()); - ATRACE_INT(counterName, connection->waitQueue.count()); - } -#endif -} - -void InputDispatcher::dump(String8& dump) { - AutoMutex _l(mLock); - - dump.append("Input Dispatcher State:\n"); - dumpDispatchStateLocked(dump); - - if (!mLastANRState.isEmpty()) { - dump.append("\nInput Dispatcher State at time of last ANR:\n"); - dump.append(mLastANRState); - } -} - -void InputDispatcher::monitor() { - // Acquire and release the lock to ensure that the dispatcher has not deadlocked. - mLock.lock(); - mLooper->wake(); - mDispatcherIsAliveCondition.wait(mLock); - mLock.unlock(); -} - - -// --- InputDispatcher::Queue --- - -template <typename T> -uint32_t InputDispatcher::Queue<T>::count() const { - uint32_t result = 0; - for (const T* entry = head; entry; entry = entry->next) { - result += 1; - } - return result; -} - - -// --- InputDispatcher::InjectionState --- - -InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : - refCount(1), - injectorPid(injectorPid), injectorUid(injectorUid), - injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), - pendingForegroundDispatches(0) { -} - -InputDispatcher::InjectionState::~InjectionState() { -} - -void InputDispatcher::InjectionState::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - - -// --- InputDispatcher::EventEntry --- - -InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) : - refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags), - injectionState(NULL), dispatchInProgress(false) { -} - -InputDispatcher::EventEntry::~EventEntry() { - releaseInjectionState(); -} - -void InputDispatcher::EventEntry::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - -void InputDispatcher::EventEntry::releaseInjectionState() { - if (injectionState) { - injectionState->release(); - injectionState = NULL; - } -} - - -// --- InputDispatcher::ConfigurationChangedEntry --- - -InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) : - EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) { -} - -InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { -} - -void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const { - msg.append("ConfigurationChangedEvent()"); -} - - -// --- InputDispatcher::DeviceResetEntry --- - -InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) : - EventEntry(TYPE_DEVICE_RESET, eventTime, 0), - deviceId(deviceId) { -} - -InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { -} - -void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const { - msg.appendFormat("DeviceResetEvent(deviceId=%d)", deviceId); -} - - -// --- InputDispatcher::KeyEntry --- - -InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime) : - EventEntry(TYPE_KEY, eventTime, policyFlags), - deviceId(deviceId), source(source), action(action), flags(flags), - keyCode(keyCode), scanCode(scanCode), metaState(metaState), - repeatCount(repeatCount), downTime(downTime), - syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), - interceptKeyWakeupTime(0) { -} - -InputDispatcher::KeyEntry::~KeyEntry() { -} - -void InputDispatcher::KeyEntry::appendDescription(String8& msg) const { - msg.appendFormat("KeyEvent(action=%d, deviceId=%d, source=0x%08x)", - action, deviceId, source); -} - -void InputDispatcher::KeyEntry::recycle() { - releaseInjectionState(); - - dispatchInProgress = false; - syntheticRepeat = false; - interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - interceptKeyWakeupTime = 0; -} - - -// --- InputDispatcher::MotionEntry --- - -InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) : - EventEntry(TYPE_MOTION, eventTime, policyFlags), - eventTime(eventTime), - deviceId(deviceId), source(source), action(action), flags(flags), - metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), - downTime(downTime), displayId(displayId), pointerCount(pointerCount) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -InputDispatcher::MotionEntry::~MotionEntry() { -} - -void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { - msg.appendFormat("MotionEvent(action=%d, deviceId=%d, source=0x%08x, displayId=%d)", - action, deviceId, source, displayId); -} - - -// --- InputDispatcher::DispatchEntry --- - -volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; - -InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : - seq(nextSeq()), - eventEntry(eventEntry), targetFlags(targetFlags), - xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), - deliveryTime(0), resolvedAction(0), resolvedFlags(0) { - eventEntry->refCount += 1; -} - -InputDispatcher::DispatchEntry::~DispatchEntry() { - eventEntry->release(); -} - -uint32_t InputDispatcher::DispatchEntry::nextSeq() { - // Sequence number 0 is reserved and will never be returned. - uint32_t seq; - do { - seq = android_atomic_inc(&sNextSeqAtomic); - } while (!seq); - return seq; -} - - -// --- InputDispatcher::InputState --- - -InputDispatcher::InputState::InputState() { -} - -InputDispatcher::InputState::~InputState() { -} - -bool InputDispatcher::InputState::isNeutral() const { - return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); -} - -bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source, - int32_t displayId) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.deviceId == deviceId - && memento.source == source - && memento.displayId == displayId - && memento.hovering) { - return true; - } - } - return false; -} - -bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, - int32_t action, int32_t flags) { - switch (action) { - case AKEY_EVENT_ACTION_UP: { - if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { - for (size_t i = 0; i < mFallbackKeys.size(); ) { - if (mFallbackKeys.valueAt(i) == entry->keyCode) { - mFallbackKeys.removeItemsAt(i); - } else { - i += 1; - } - } - } - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.removeAt(index); - return true; - } - /* FIXME: We can't just drop the key up event because that prevents creating - * popup windows that are automatically shown when a key is held and then - * dismissed when the key is released. The problem is that the popup will - * not have received the original key down, so the key up will be considered - * to be inconsistent with its observed state. We could perhaps handle this - * by synthesizing a key down but that will cause other problems. - * - * So for now, allow inconsistent key up events to be dispatched. - * -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " - "keyCode=%d, scanCode=%d", - entry->deviceId, entry->source, entry->keyCode, entry->scanCode); -#endif - return false; - */ - return true; - } - - case AKEY_EVENT_ACTION_DOWN: { - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.removeAt(index); - } - addKeyMemento(entry, flags); - return true; - } - - default: - return true; - } -} - -bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, - int32_t action, int32_t flags) { - int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; - switch (actionMasked) { - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " - "actionMasked=%d", - entry->deviceId, entry->source, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - } - addMotionMemento(entry, flags, false /*hovering*/); - return true; - } - - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_MOVE: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - MotionMemento& memento = mMotionMementos.editItemAt(index); - memento.setPointers(entry); - return true; - } - if (actionMasked == AMOTION_EVENT_ACTION_MOVE - && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK - | AINPUT_SOURCE_CLASS_NAVIGATION))) { - // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion pointer up/down or move event: " - "deviceId=%d, source=%08x, actionMasked=%d", - entry->deviceId, entry->source, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_EXIT: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x", - entry->deviceId, entry->source); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - } - addMotionMemento(entry, flags, true /*hovering*/); - return true; - } - - default: - return true; - } -} - -ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.keyCode == entry->keyCode - && memento.scanCode == entry->scanCode) { - return i; - } - } - return -1; -} - -ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, - bool hovering) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.displayId == entry->displayId - && memento.hovering == hovering) { - return i; - } - } - return -1; -} - -void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { - mKeyMementos.push(); - KeyMemento& memento = mKeyMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.keyCode = entry->keyCode; - memento.scanCode = entry->scanCode; - memento.metaState = entry->metaState; - memento.flags = flags; - memento.downTime = entry->downTime; - memento.policyFlags = entry->policyFlags; -} - -void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, - int32_t flags, bool hovering) { - mMotionMementos.push(); - MotionMemento& memento = mMotionMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.flags = flags; - memento.xPrecision = entry->xPrecision; - memento.yPrecision = entry->yPrecision; - memento.downTime = entry->downTime; - memento.displayId = entry->displayId; - memento.setPointers(entry); - memento.hovering = hovering; - memento.policyFlags = entry->policyFlags; -} - -void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { - pointerCount = entry->pointerCount; - for (uint32_t i = 0; i < entry->pointerCount; i++) { - pointerProperties[i].copyFrom(entry->pointerProperties[i]); - pointerCoords[i].copyFrom(entry->pointerCoords[i]); - } -} - -void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, - Vector<EventEntry*>& outEvents, const CancelationOptions& options) { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (shouldCancelKey(memento, options)) { - outEvents.push(new KeyEntry(currentTime, - memento.deviceId, memento.source, memento.policyFlags, - AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); - } - } - - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (shouldCancelMotion(memento, options)) { - outEvents.push(new MotionEntry(currentTime, - memento.deviceId, memento.source, memento.policyFlags, - memento.hovering - ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL, - memento.flags, 0, 0, 0, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.displayId, - memento.pointerCount, memento.pointerProperties, memento.pointerCoords)); - } - } -} - -void InputDispatcher::InputState::clear() { - mKeyMementos.clear(); - mMotionMementos.clear(); - mFallbackKeys.clear(); -} - -void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { - for (size_t j = 0; j < other.mMotionMementos.size(); ) { - const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); - if (memento.deviceId == otherMemento.deviceId - && memento.source == otherMemento.source - && memento.displayId == otherMemento.displayId) { - other.mMotionMementos.removeAt(j); - } else { - j += 1; - } - } - other.mMotionMementos.push(memento); - } - } -} - -int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - return index >= 0 ? mFallbackKeys.valueAt(index) : -1; -} - -void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, - int32_t fallbackKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - if (index >= 0) { - mFallbackKeys.replaceValueAt(index, fallbackKeyCode); - } else { - mFallbackKeys.add(originalKeyCode, fallbackKeyCode); - } -} - -void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { - mFallbackKeys.removeItem(originalKeyCode); -} - -bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options) { - if (options.keyCode != -1 && memento.keyCode != options.keyCode) { - return false; - } - - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return true; - case CancelationOptions::CANCEL_FALLBACK_EVENTS: - return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - default: - return false; - } -} - -bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options) { - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - return true; - case CancelationOptions::CANCEL_POINTER_EVENTS: - return memento.source & AINPUT_SOURCE_CLASS_POINTER; - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - default: - return false; - } -} - - -// --- InputDispatcher::Connection --- - -InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) : - status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), - monitor(monitor), - inputPublisher(inputChannel), inputPublisherBlocked(false) { -} - -InputDispatcher::Connection::~Connection() { -} - -const char* InputDispatcher::Connection::getWindowName() const { - if (inputWindowHandle != NULL) { - return inputWindowHandle->getName().string(); - } - if (monitor) { - return "monitor"; - } - return "?"; -} - -const char* InputDispatcher::Connection::getStatusLabel() const { - switch (status) { - case STATUS_NORMAL: - return "NORMAL"; - - case STATUS_BROKEN: - return "BROKEN"; - - case STATUS_ZOMBIE: - return "ZOMBIE"; - - default: - return "UNKNOWN"; - } -} - -InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { - for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) { - if (entry->seq == seq) { - return entry; - } - } - return NULL; -} - - -// --- InputDispatcher::CommandEntry --- - -InputDispatcher::CommandEntry::CommandEntry(Command command) : - command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), - seq(0), handled(false) { -} - -InputDispatcher::CommandEntry::~CommandEntry() { -} - - -// --- InputDispatcher::TouchState --- - -InputDispatcher::TouchState::TouchState() : - down(false), split(false), deviceId(-1), source(0), displayId(-1) { -} - -InputDispatcher::TouchState::~TouchState() { -} - -void InputDispatcher::TouchState::reset() { - down = false; - split = false; - deviceId = -1; - source = 0; - displayId = -1; - windows.clear(); -} - -void InputDispatcher::TouchState::copyFrom(const TouchState& other) { - down = other.down; - split = other.split; - deviceId = other.deviceId; - source = other.source; - displayId = other.displayId; - windows = other.windows; -} - -void InputDispatcher::TouchState::addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds) { - if (targetFlags & InputTarget::FLAG_SPLIT) { - split = true; - } - - for (size_t i = 0; i < windows.size(); i++) { - TouchedWindow& touchedWindow = windows.editItemAt(i); - if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.targetFlags |= targetFlags; - if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; - } - touchedWindow.pointerIds.value |= pointerIds.value; - return; - } - } - - windows.push(); - - TouchedWindow& touchedWindow = windows.editTop(); - touchedWindow.windowHandle = windowHandle; - touchedWindow.targetFlags = targetFlags; - touchedWindow.pointerIds = pointerIds; -} - -void InputDispatcher::TouchState::removeWindow(const sp<InputWindowHandle>& windowHandle) { - for (size_t i = 0; i < windows.size(); i++) { - if (windows.itemAt(i).windowHandle == windowHandle) { - windows.removeAt(i); - return; - } - } -} - -void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { - for (size_t i = 0 ; i < windows.size(); ) { - TouchedWindow& window = windows.editItemAt(i); - if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { - window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; - window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; - i += 1; - } else { - windows.removeAt(i); - } - } -} - -sp<InputWindowHandle> InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows.itemAt(i); - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - return window.windowHandle; - } - } - return NULL; -} - -bool InputDispatcher::TouchState::isSlippery() const { - // Must have exactly one foreground window. - bool haveSlipperyForegroundWindow = false; - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows.itemAt(i); - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - if (haveSlipperyForegroundWindow - || !(window.windowHandle->getInfo()->layoutParamsFlags - & InputWindowInfo::FLAG_SLIPPERY)) { - return false; - } - haveSlipperyForegroundWindow = true; - } - } - return haveSlipperyForegroundWindow; -} - - -// --- InputDispatcherThread --- - -InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) : - Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { -} - -InputDispatcherThread::~InputDispatcherThread() { -} - -bool InputDispatcherThread::threadLoop() { - mDispatcher->dispatchOnce(); - return true; -} - -} // namespace android diff --git a/widget/gonk/libui/InputDispatcher.h b/widget/gonk/libui/InputDispatcher.h deleted file mode 100644 index 5453421f6..000000000 --- a/widget/gonk/libui/InputDispatcher.h +++ /dev/null @@ -1,1117 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_INPUT_DISPATCHER_H -#define _UI_INPUT_DISPATCHER_H - -#include "Input.h" -#include "InputTransport.h" -#include <utils/KeyedVector.h> -#include <utils/Vector.h> -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/Looper.h> -#include <utils/BitSet.h> -#include <cutils/atomic.h> - -#include <stddef.h> -#include <unistd.h> -#include <limits.h> - -#include "InputWindow.h" -#include "InputApplication.h" -#include "InputListener.h" - - -namespace android { - -/* - * Constants used to report the outcome of input event injection. - */ -enum { - /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ - INPUT_EVENT_INJECTION_PENDING = -1, - - /* Injection succeeded. */ - INPUT_EVENT_INJECTION_SUCCEEDED = 0, - - /* Injection failed because the injector did not have permission to inject - * into the application with input focus. */ - INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, - - /* Injection failed because there were no available input targets. */ - INPUT_EVENT_INJECTION_FAILED = 2, - - /* Injection failed due to a timeout. */ - INPUT_EVENT_INJECTION_TIMED_OUT = 3 -}; - -/* - * Constants used to determine the input event injection synchronization mode. - */ -enum { - /* Injection is asynchronous and is assumed always to be successful. */ - INPUT_EVENT_INJECTION_SYNC_NONE = 0, - - /* Waits for previous events to be dispatched so that the input dispatcher can determine - * whether input event injection willbe permitted based on the current input focus. - * Does not wait for the input event to finish processing. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, - - /* Waits for the input event to be completely processed. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, -}; - - -/* - * An input target specifies how an input event is to be dispatched to a particular window - * including the window's input channel, control flags, a timeout, and an X / Y offset to - * be added to input event coordinates to compensate for the absolute position of the - * window area. - */ -struct InputTarget { - enum { - /* This flag indicates that the event is being delivered to a foreground application. */ - FLAG_FOREGROUND = 1 << 0, - - /* This flag indicates that the target of a MotionEvent is partly or wholly - * obscured by another visible window above it. The motion event should be - * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ - FLAG_WINDOW_IS_OBSCURED = 1 << 1, - - /* This flag indicates that a motion event is being split across multiple windows. */ - FLAG_SPLIT = 1 << 2, - - /* This flag indicates that the pointer coordinates dispatched to the application - * will be zeroed out to avoid revealing information to an application. This is - * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing - * the same UID from watching all touches. */ - FLAG_ZERO_COORDS = 1 << 3, - - /* This flag indicates that the event should be sent as is. - * Should always be set unless the event is to be transmuted. */ - FLAG_DISPATCH_AS_IS = 1 << 8, - - /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside - * of the area of this target and so should instead be delivered as an - * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ - FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, - - /* This flag indicates that a hover sequence is starting in the given window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, - - /* This flag indicates that a hover event happened outside of a window which handled - * previous hover events, signifying the end of the current hover sequence for that - * window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, - - /* This flag indicates that the event should be canceled. - * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips - * outside of a window. */ - FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, - - /* This flag indicates that the event should be dispatched as an initial down. - * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips - * into a new window. */ - FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, - - /* Mask for all dispatch modes. */ - FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS - | FLAG_DISPATCH_AS_OUTSIDE - | FLAG_DISPATCH_AS_HOVER_ENTER - | FLAG_DISPATCH_AS_HOVER_EXIT - | FLAG_DISPATCH_AS_SLIPPERY_EXIT - | FLAG_DISPATCH_AS_SLIPPERY_ENTER, - }; - - // The input channel to be targeted. - sp<InputChannel> inputChannel; - - // Flags for the input target. - int32_t flags; - - // The x and y offset to add to a MotionEvent as it is delivered. - // (ignored for KeyEvents) - float xOffset, yOffset; - - // Scaling factor to apply to MotionEvent as it is delivered. - // (ignored for KeyEvents) - float scaleFactor; - - // The subset of pointer ids to include in motion events dispatched to this input target - // if FLAG_SPLIT is set. - BitSet32 pointerIds; -}; - - -/* - * Input dispatcher configuration. - * - * Specifies various options that modify the behavior of the input dispatcher. - * The values provided here are merely defaults. The actual values will come from ViewConfiguration - * and are passed into the dispatcher during initialization. - */ -struct InputDispatcherConfiguration { - // The key repeat initial timeout. - nsecs_t keyRepeatTimeout; - - // The key repeat inter-key delay. - nsecs_t keyRepeatDelay; - - InputDispatcherConfiguration() : - keyRepeatTimeout(500 * 1000000LL), - keyRepeatDelay(50 * 1000000LL) { } -}; - - -/* - * Input dispatcher policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class InputDispatcherPolicyInterface : public virtual RefBase { -protected: - InputDispatcherPolicyInterface() { } - virtual ~InputDispatcherPolicyInterface() { } - -public: - /* Notifies the system that a configuration change has occurred. */ - virtual void notifyConfigurationChanged(nsecs_t when) = 0; - - /* Notifies the system that an application is not responding. - * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ - virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle, - const sp<InputWindowHandle>& inputWindowHandle) = 0; - - /* Notifies the system that an input channel is unrecoverably broken. */ - virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0; - - /* Gets the input dispatcher configuration. */ - virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; - - /* Returns true if automatic key repeating is enabled. */ - virtual bool isKeyRepeatEnabled() = 0; - - /* Filters an input event. - * Return true to dispatch the event unmodified, false to consume the event. - * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED - * to injectInputEvent. - */ - virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; - - /* Intercepts a key event immediately before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; - - /* Intercepts a touch, trackball or other motion event before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; - - /* Allows the policy a chance to intercept a key before dispatching. */ - virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags) = 0; - - /* Allows the policy a chance to perform default processing for an unhandled key. - * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ - virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; - - /* Notifies the policy about switch events. - */ - virtual void notifySwitch(nsecs_t when, - uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) = 0; - - /* Poke user activity for an event dispatched to a window. */ - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; - - /* Checks whether a given application pid/uid has permission to inject input events - * into other applications. - * - * This method is special in that its implementation promises to be non-reentrant and - * is safe to call while holding other locks. (Most other methods make no such guarantees!) - */ - virtual bool checkInjectEventsPermissionNonReentrant( - int32_t injectorPid, int32_t injectorUid) = 0; -}; - - -/* Notifies the system about input events generated by the input reader. - * The dispatcher is expected to be mostly asynchronous. */ -class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { -protected: - InputDispatcherInterface() { } - virtual ~InputDispatcherInterface() { } - -public: - /* Dumps the state of the input dispatcher. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the dispatch loop. - * Nominally processes one queued event, a timeout, or a response from an input consumer. - * - * This method should only be called on the input dispatcher thread. - */ - virtual void dispatchOnce() = 0; - - /* Injects an input event and optionally waits for sync. - * The synchronization mode determines whether the method blocks while waiting for - * input injection to proceed. - * Returns one of the INPUT_EVENT_INJECTION_XXX constants. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) = 0; - - /* Sets the list of input windows. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles) = 0; - - /* Sets the focused application. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setFocusedApplication( - const sp<InputApplicationHandle>& inputApplicationHandle) = 0; - - /* Sets the input dispatching mode. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; - - /* Sets whether input event filtering is enabled. - * When enabled, incoming input events are sent to the policy's filterInputEvent - * method instead of being dispatched. The filter is expected to use - * injectInputEvent to inject the events it would like to have dispatched. - * It should include POLICY_FLAG_FILTERED in the policy flags during injection. - */ - virtual void setInputFilterEnabled(bool enabled) = 0; - - /* Transfers touch focus from the window associated with one channel to the - * window associated with the other channel. - * - * Returns true on success. False if the window did not actually have touch focus. - */ - virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) = 0; - - /* Registers or unregister input channels that may be used as targets for input events. - * If monitor is true, the channel will receive a copy of all input events. - * - * These methods may be called on any thread (usually by the input manager). - */ - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) = 0; - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel) = 0; -}; - -/* Dispatches events to input targets. Some functions of the input dispatcher, such as - * identifying input targets, are controlled by a separate policy object. - * - * IMPORTANT INVARIANT: - * Because the policy can potentially block or cause re-entrance into the input dispatcher, - * the input dispatcher never calls into the policy while holding its internal locks. - * The implementation is also carefully designed to recover from scenarios such as an - * input channel becoming unregistered while identifying input targets or processing timeouts. - * - * Methods marked 'Locked' must be called with the lock acquired. - * - * Methods marked 'LockedInterruptible' must be called with the lock acquired but - * may during the course of their execution release the lock, call into the policy, and - * then reacquire the lock. The caller is responsible for recovering gracefully. - * - * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. - */ -class InputDispatcher : public InputDispatcherInterface { -protected: - virtual ~InputDispatcher(); - -public: - explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy); - - virtual void dump(String8& dump); - virtual void monitor(); - - virtual void dispatchOnce(); - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags); - - virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles); - virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle); - virtual void setInputDispatchMode(bool enabled, bool frozen); - virtual void setInputFilterEnabled(bool enabled); - - virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel); - - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor); - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); - -private: - template <typename T> - struct Link { - T* next; - T* prev; - - protected: - inline Link() : next(NULL), prev(NULL) { } - }; - - struct InjectionState { - mutable int32_t refCount; - - int32_t injectorPid; - int32_t injectorUid; - int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING - bool injectionIsAsync; // set to true if injection is not waiting for the result - int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress - - InjectionState(int32_t injectorPid, int32_t injectorUid); - void release(); - - private: - ~InjectionState(); - }; - - struct EventEntry : Link<EventEntry> { - enum { - TYPE_CONFIGURATION_CHANGED, - TYPE_DEVICE_RESET, - TYPE_KEY, - TYPE_MOTION - }; - - mutable int32_t refCount; - int32_t type; - nsecs_t eventTime; - uint32_t policyFlags; - InjectionState* injectionState; - - bool dispatchInProgress; // initially false, set to true while dispatching - - inline bool isInjected() const { return injectionState != NULL; } - - void release(); - - virtual void appendDescription(String8& msg) const = 0; - - protected: - EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); - virtual ~EventEntry(); - void releaseInjectionState(); - }; - - struct ConfigurationChangedEntry : EventEntry { - ConfigurationChangedEntry(nsecs_t eventTime); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~ConfigurationChangedEntry(); - }; - - struct DeviceResetEntry : EventEntry { - int32_t deviceId; - - DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~DeviceResetEntry(); - }; - - struct KeyEntry : EventEntry { - int32_t deviceId; - uint32_t source; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t repeatCount; - nsecs_t downTime; - - bool syntheticRepeat; // set to true for synthetic key repeats - - enum InterceptKeyResult { - INTERCEPT_KEY_RESULT_UNKNOWN, - INTERCEPT_KEY_RESULT_SKIP, - INTERCEPT_KEY_RESULT_CONTINUE, - INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, - }; - InterceptKeyResult interceptKeyResult; // set based on the interception result - nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER - - KeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime); - virtual void appendDescription(String8& msg) const; - void recycle(); - - protected: - virtual ~KeyEntry(); - }; - - struct MotionEntry : EventEntry { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - - MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, int32_t edgeFlags, - float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~MotionEntry(); - }; - - // Tracks the progress of dispatching a particular event to a particular connection. - struct DispatchEntry : Link<DispatchEntry> { - const uint32_t seq; // unique sequence number, never 0 - - EventEntry* eventEntry; // the event to dispatch - int32_t targetFlags; - float xOffset; - float yOffset; - float scaleFactor; - nsecs_t deliveryTime; // time when the event was actually delivered - - // Set to the resolved action and flags when the event is enqueued. - int32_t resolvedAction; - int32_t resolvedFlags; - - DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); - ~DispatchEntry(); - - inline bool hasForegroundTarget() const { - return targetFlags & InputTarget::FLAG_FOREGROUND; - } - - inline bool isSplit() const { - return targetFlags & InputTarget::FLAG_SPLIT; - } - - private: - static volatile int32_t sNextSeqAtomic; - - static uint32_t nextSeq(); - }; - - // A command entry captures state and behavior for an action to be performed in the - // dispatch loop after the initial processing has taken place. It is essentially - // a kind of continuation used to postpone sensitive policy interactions to a point - // in the dispatch loop where it is safe to release the lock (generally after finishing - // the critical parts of the dispatch cycle). - // - // The special thing about commands is that they can voluntarily release and reacquire - // the dispatcher lock at will. Initially when the command starts running, the - // dispatcher lock is held. However, if the command needs to call into the policy to - // do some work, it can release the lock, do the work, then reacquire the lock again - // before returning. - // - // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch - // never calls into the policy while holding its lock. - // - // Commands are implicitly 'LockedInterruptible'. - struct CommandEntry; - typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); - - class Connection; - struct CommandEntry : Link<CommandEntry> { - CommandEntry(Command command); - ~CommandEntry(); - - Command command; - - // parameters for the command (usage varies by command) - sp<Connection> connection; - nsecs_t eventTime; - KeyEntry* keyEntry; - sp<InputApplicationHandle> inputApplicationHandle; - sp<InputWindowHandle> inputWindowHandle; - int32_t userActivityEventType; - uint32_t seq; - bool handled; - }; - - // Generic queue implementation. - template <typename T> - struct Queue { - T* head; - T* tail; - - inline Queue() : head(NULL), tail(NULL) { - } - - inline bool isEmpty() const { - return !head; - } - - inline void enqueueAtTail(T* entry) { - entry->prev = tail; - if (tail) { - tail->next = entry; - } else { - head = entry; - } - entry->next = NULL; - tail = entry; - } - - inline void enqueueAtHead(T* entry) { - entry->next = head; - if (head) { - head->prev = entry; - } else { - tail = entry; - } - entry->prev = NULL; - head = entry; - } - - inline void dequeue(T* entry) { - if (entry->prev) { - entry->prev->next = entry->next; - } else { - head = entry->next; - } - if (entry->next) { - entry->next->prev = entry->prev; - } else { - tail = entry->prev; - } - } - - inline T* dequeueAtHead() { - T* entry = head; - head = entry->next; - if (head) { - head->prev = NULL; - } else { - tail = NULL; - } - return entry; - } - - uint32_t count() const; - }; - - /* Specifies which events are to be canceled and why. */ - struct CancelationOptions { - enum Mode { - CANCEL_ALL_EVENTS = 0, - CANCEL_POINTER_EVENTS = 1, - CANCEL_NON_POINTER_EVENTS = 2, - CANCEL_FALLBACK_EVENTS = 3, - }; - - // The criterion to use to determine which events should be canceled. - Mode mode; - - // Descriptive reason for the cancelation. - const char* reason; - - // The specific keycode of the key event to cancel, or -1 to cancel any key event. - int32_t keyCode; - - // The specific device id of events to cancel, or -1 to cancel events from any device. - int32_t deviceId; - - CancelationOptions(Mode mode, const char* reason) : - mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } - }; - - /* Tracks dispatched key and motion event state so that cancelation events can be - * synthesized when events are dropped. */ - class InputState { - public: - InputState(); - ~InputState(); - - // Returns true if there is no state to be canceled. - bool isNeutral() const; - - // Returns true if the specified source is known to have received a hover enter - // motion event. - bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; - - // Records tracking information for a key event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); - - // Records tracking information for a motion event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); - - // Synthesizes cancelation events for the current state and resets the tracked state. - void synthesizeCancelationEvents(nsecs_t currentTime, - Vector<EventEntry*>& outEvents, const CancelationOptions& options); - - // Clears the current state. - void clear(); - - // Copies pointer-related parts of the input state to another instance. - void copyPointerStateTo(InputState& other) const; - - // Gets the fallback key associated with a keycode. - // Returns -1 if none. - // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. - int32_t getFallbackKey(int32_t originalKeyCode); - - // Sets the fallback key for a particular keycode. - void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); - - // Removes the fallback key for a particular keycode. - void removeFallbackKey(int32_t originalKeyCode); - - inline const KeyedVector<int32_t, int32_t>& getFallbackKeys() const { - return mFallbackKeys; - } - - private: - struct KeyMemento { - int32_t deviceId; - uint32_t source; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t flags; - nsecs_t downTime; - uint32_t policyFlags; - }; - - struct MotionMemento { - int32_t deviceId; - uint32_t source; - int32_t flags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - bool hovering; - uint32_t policyFlags; - - void setPointers(const MotionEntry* entry); - }; - - Vector<KeyMemento> mKeyMementos; - Vector<MotionMemento> mMotionMementos; - KeyedVector<int32_t, int32_t> mFallbackKeys; - - ssize_t findKeyMemento(const KeyEntry* entry) const; - ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; - - void addKeyMemento(const KeyEntry* entry, int32_t flags); - void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); - - static bool shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options); - static bool shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options); - }; - - /* Manages the dispatch state associated with a single input channel. */ - class Connection : public RefBase { - protected: - virtual ~Connection(); - - public: - enum Status { - // Everything is peachy. - STATUS_NORMAL, - // An unrecoverable communication error has occurred. - STATUS_BROKEN, - // The input channel has been unregistered. - STATUS_ZOMBIE - }; - - Status status; - sp<InputChannel> inputChannel; // never null - sp<InputWindowHandle> inputWindowHandle; // may be null - bool monitor; - InputPublisher inputPublisher; - InputState inputState; - - // True if the socket is full and no further events can be published until - // the application consumes some of the input. - bool inputPublisherBlocked; - - // Queue of events that need to be published to the connection. - Queue<DispatchEntry> outboundQueue; - - // Queue of events that have been published to the connection but that have not - // yet received a "finished" response from the application. - Queue<DispatchEntry> waitQueue; - - explicit Connection(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor); - - inline const char* getInputChannelName() const { return inputChannel->getName().string(); } - - const char* getWindowName() const; - const char* getStatusLabel() const; - - DispatchEntry* findWaitQueueEntry(uint32_t seq); - }; - - enum DropReason { - DROP_REASON_NOT_DROPPED = 0, - DROP_REASON_POLICY = 1, - DROP_REASON_APP_SWITCH = 2, - DROP_REASON_DISABLED = 3, - DROP_REASON_BLOCKED = 4, - DROP_REASON_STALE = 5, - }; - - sp<InputDispatcherPolicyInterface> mPolicy; - InputDispatcherConfiguration mConfig; - - Mutex mLock; - - Condition mDispatcherIsAliveCondition; - - sp<Looper> mLooper; - - EventEntry* mPendingEvent; - Queue<EventEntry> mInboundQueue; - Queue<CommandEntry> mCommandQueue; - - void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); - - // Enqueues an inbound event. Returns true if mLooper->wake() should be called. - bool enqueueInboundEventLocked(EventEntry* entry); - - // Cleans up input state when dropping an inbound event. - void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); - - // App switch latency optimization. - bool mAppSwitchSawKeyDown; - nsecs_t mAppSwitchDueTime; - - static bool isAppSwitchKeyCode(int32_t keyCode); - bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); - bool isAppSwitchPendingLocked(); - void resetPendingAppSwitchLocked(bool handled); - - // Stale event latency optimization. - static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); - - // Blocked event latency optimization. Drops old events when the user intends - // to transfer focus to a new application. - EventEntry* mNextUnblockedEvent; - - sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y); - - // All registered connections mapped by channel file descriptor. - KeyedVector<int, sp<Connection> > mConnectionsByFd; - - ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel); - - // Input channels that will receive a copy of all input events. - Vector<sp<InputChannel> > mMonitoringChannels; - - // Event injection and synchronization. - Condition mInjectionResultAvailableCondition; - bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); - void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); - - Condition mInjectionSyncFinishedCondition; - void incrementPendingForegroundDispatchesLocked(EventEntry* entry); - void decrementPendingForegroundDispatchesLocked(EventEntry* entry); - - // Key repeat tracking. - struct KeyRepeatState { - KeyEntry* lastKeyEntry; // or null if no repeat - nsecs_t nextRepeatTime; - } mKeyRepeatState; - - void resetKeyRepeatLocked(); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); - - // Deferred command processing. - bool haveCommandsLocked() const; - bool runCommandsLockedInterruptible(); - CommandEntry* postCommandLocked(Command command); - - // Input filter processing. - bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args); - bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args); - - // Inbound event processing. - void drainInboundQueueLocked(); - void releasePendingEventLocked(); - void releaseInboundEventLocked(EventEntry* entry); - - // Dispatch state. - bool mDispatchEnabled; - bool mDispatchFrozen; - bool mInputFilterEnabled; - - Vector<sp<InputWindowHandle> > mWindowHandles; - - sp<InputWindowHandle> getWindowHandleLocked(const sp<InputChannel>& inputChannel) const; - bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const; - - // Focus tracking for keys, trackball, etc. - sp<InputWindowHandle> mFocusedWindowHandle; - - // Focus tracking for touch. - struct TouchedWindow { - sp<InputWindowHandle> windowHandle; - int32_t targetFlags; - BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set - }; - struct TouchState { - bool down; - bool split; - int32_t deviceId; // id of the device that is currently down, others are rejected - uint32_t source; // source of the device that is current down, others are rejected - int32_t displayId; // id to the display that currently has a touch, others are rejected - Vector<TouchedWindow> windows; - - TouchState(); - ~TouchState(); - void reset(); - void copyFrom(const TouchState& other); - void addOrUpdateWindow(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds); - void removeWindow(const sp<InputWindowHandle>& windowHandle); - void filterNonAsIsTouchWindows(); - sp<InputWindowHandle> getFirstForegroundWindowHandle() const; - bool isSlippery() const; - }; - - TouchState mTouchState; - TouchState mTempTouchState; - - // Focused application. - sp<InputApplicationHandle> mFocusedApplicationHandle; - - // Dispatcher state at time of last ANR. - String8 mLastANRState; - - // Dispatch inbound events. - bool dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry); - bool dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry); - bool dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime); - bool dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime); - void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, - const Vector<InputTarget>& inputTargets); - - void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry); - void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry); - - // Keeping track of ANR timeouts. - enum InputTargetWaitCause { - INPUT_TARGET_WAIT_CAUSE_NONE, - INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, - INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, - }; - - InputTargetWaitCause mInputTargetWaitCause; - nsecs_t mInputTargetWaitStartTime; - nsecs_t mInputTargetWaitTimeoutTime; - bool mInputTargetWaitTimeoutExpired; - sp<InputApplicationHandle> mInputTargetWaitApplicationHandle; - - // Contains the last window which received a hover event. - sp<InputWindowHandle> mLastHoverWindowHandle; - - // Finding targets for input events. - int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, - const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t* nextWakeupTime, const char* reason); - void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp<InputChannel>& inputChannel); - nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); - void resetANRTimeoutsLocked(); - - int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, - Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime); - int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, - Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions); - - void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets); - void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets); - - void pokeUserActivityLocked(const EventEntry* eventEntry); - bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle, - const InjectionState* injectionState); - bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, - int32_t x, int32_t y) const; - bool isWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry); - String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle); - - // Manage the dispatch cycle for a single connection. - // These methods are deliberately not Interruptible because doing all of the work - // with the mutex held makes it easier to ensure that connection invariants are maintained. - // If needed, the methods post commands to run later once the critical bits are done. - void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget); - void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget); - void enqueueDispatchEntryLocked(const sp<Connection>& connection, - EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode); - void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection); - void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - uint32_t seq, bool handled); - void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, - bool notify); - void drainDispatchQueueLocked(Queue<DispatchEntry>* queue); - void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry); - static int handleReceiveCallback(int fd, int events, void* data); - - void synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options); - void synthesizeCancelationEventsForInputChannelLocked(const sp<InputChannel>& channel, - const CancelationOptions& options); - void synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, - const CancelationOptions& options); - - // Splitting motion events across windows. - MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); - - // Reset and drop everything the dispatcher is doing. - void resetAndDropEverythingLocked(const char* reason); - - // Dump state. - void dumpDispatchStateLocked(String8& dump); - void logDispatchStateLocked(); - - // Registration. - void removeMonitorChannelLocked(const sp<InputChannel>& inputChannel); - status_t unregisterInputChannelLocked(const sp<InputChannel>& inputChannel, bool notify); - - // Add or remove a connection to the mActiveConnections vector. - void activateConnectionLocked(Connection* connection); - void deactivateConnectionLocked(Connection* connection); - - // Interesting events that we might like to log or tell the framework about. - void onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled); - void onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp<Connection>& connection); - void onANRLocked( - nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle, - const sp<InputWindowHandle>& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason); - - // Outbound policy interactions. - void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry); - void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); - void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); - void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); - void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry); - bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled); - bool afterMotionEventLockedInterruptible(const sp<Connection>& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled); - void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); - void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); - - // Statistics gathering. - void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); - void traceInboundQueueLengthLocked(); - void traceOutboundQueueLengthLocked(const sp<Connection>& connection); - void traceWaitQueueLengthLocked(const sp<Connection>& connection); -}; - -/* Enqueues and dispatches input events, endlessly. */ -class InputDispatcherThread : public Thread { -public: - explicit InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher); - ~InputDispatcherThread(); - -private: - virtual bool threadLoop(); - - sp<InputDispatcherInterface> mDispatcher; -}; - -} // namespace android - -#endif // _UI_INPUT_DISPATCHER_H diff --git a/widget/gonk/libui/InputListener.cpp b/widget/gonk/libui/InputListener.cpp deleted file mode 100644 index 3b673f0ad..000000000 --- a/widget/gonk/libui/InputListener.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputListener" - -//#define LOG_NDEBUG 0 - -#include "InputListener.h" - -#include "cutils_log.h" - -namespace android { - -// --- NotifyConfigurationChangedArgs --- - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) : - eventTime(eventTime) { -} - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( - const NotifyConfigurationChangedArgs& other) : - eventTime(other.eventTime) { -} - -void NotifyConfigurationChangedArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyConfigurationChanged(this); -} - - -// --- NotifyKeyArgs --- - -NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime) : - eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), - metaState(metaState), downTime(downTime) { -} - -NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), - policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - keyCode(other.keyCode), scanCode(other.scanCode), - metaState(other.metaState), downTime(other.downTime) { -} - -void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyKey(this); -} - - -// --- NotifyMotionArgs --- - -NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime) : - eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), metaState(metaState), buttonState(buttonState), - edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount), - xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), - policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - metaState(other.metaState), buttonState(other.buttonState), - edgeFlags(other.edgeFlags), displayId(other.displayId), - pointerCount(other.pointerCount), - xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - } -} - -void NotifyMotionArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyMotion(this); -} - - -// --- NotifySwitchArgs --- - -NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask) : - eventTime(eventTime), policyFlags(policyFlags), - switchValues(switchValues), switchMask(switchMask) { -} - -NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) : - eventTime(other.eventTime), policyFlags(other.policyFlags), - switchValues(other.switchValues), switchMask(other.switchMask) { -} - -void NotifySwitchArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifySwitch(this); -} - - -// --- NotifyDeviceResetArgs --- - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) : - eventTime(eventTime), deviceId(deviceId) { -} - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId) { -} - -void NotifyDeviceResetArgs::notify(const sp<InputListenerInterface>& listener) const { - listener->notifyDeviceReset(this); -} - - -// --- QueuedInputListener --- - -QueuedInputListener::QueuedInputListener(const sp<InputListenerInterface>& innerListener) : - mInnerListener(innerListener) { -} - -QueuedInputListener::~QueuedInputListener() { - size_t count = mArgsQueue.size(); - for (size_t i = 0; i < count; i++) { - delete mArgsQueue[i]; - } -} - -void QueuedInputListener::notifyConfigurationChanged( - const NotifyConfigurationChangedArgs* args) { - mArgsQueue.push(new NotifyConfigurationChangedArgs(*args)); -} - -void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { - mArgsQueue.push(new NotifyKeyArgs(*args)); -} - -void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { - mArgsQueue.push(new NotifyMotionArgs(*args)); -} - -void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { - mArgsQueue.push(new NotifySwitchArgs(*args)); -} - -void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { - mArgsQueue.push(new NotifyDeviceResetArgs(*args)); -} - -void QueuedInputListener::flush() { - size_t count = mArgsQueue.size(); - for (size_t i = 0; i < count; i++) { - NotifyArgs* args = mArgsQueue[i]; - args->notify(mInnerListener); - delete args; - } - mArgsQueue.clear(); -} - - -} // namespace android diff --git a/widget/gonk/libui/InputListener.h b/widget/gonk/libui/InputListener.h deleted file mode 100644 index de799322f..000000000 --- a/widget/gonk/libui/InputListener.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_INPUT_LISTENER_H -#define _UI_INPUT_LISTENER_H - -#include "Input.h" -#include <utils/RefBase.h> -#include <utils/Vector.h> - -namespace android { - -class InputListenerInterface; - - -/* Superclass of all input event argument objects */ -struct NotifyArgs { - virtual ~NotifyArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const = 0; -}; - - -/* Describes a configuration change event. */ -struct NotifyConfigurationChangedArgs : public NotifyArgs { - nsecs_t eventTime; - - inline NotifyConfigurationChangedArgs() { } - - NotifyConfigurationChangedArgs(nsecs_t eventTime); - - NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); - - virtual ~NotifyConfigurationChangedArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a key event. */ -struct NotifyKeyArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - nsecs_t downTime; - - inline NotifyKeyArgs() { } - - NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime); - - NotifyKeyArgs(const NotifyKeyArgs& other); - - virtual ~NotifyKeyArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a motion event. */ -struct NotifyMotionArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - float xPrecision; - float yPrecision; - nsecs_t downTime; - - inline NotifyMotionArgs() { } - - NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime); - - NotifyMotionArgs(const NotifyMotionArgs& other); - - virtual ~NotifyMotionArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a switch event. */ -struct NotifySwitchArgs : public NotifyArgs { - nsecs_t eventTime; - uint32_t policyFlags; - uint32_t switchValues; - uint32_t switchMask; - - inline NotifySwitchArgs() { } - - NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask); - - NotifySwitchArgs(const NotifySwitchArgs& other); - - virtual ~NotifySwitchArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* Describes a device reset event, such as when a device is added, - * reconfigured, or removed. */ -struct NotifyDeviceResetArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - - inline NotifyDeviceResetArgs() { } - - NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId); - - NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); - - virtual ~NotifyDeviceResetArgs() { } - - virtual void notify(const sp<InputListenerInterface>& listener) const; -}; - - -/* - * The interface used by the InputReader to notify the InputListener about input events. - */ -class InputListenerInterface : public virtual RefBase { -protected: - InputListenerInterface() { } - virtual ~InputListenerInterface() { } - -public: - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0; - virtual void notifyKey(const NotifyKeyArgs* args) = 0; - virtual void notifyMotion(const NotifyMotionArgs* args) = 0; - virtual void notifySwitch(const NotifySwitchArgs* args) = 0; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; -}; - - -/* - * An implementation of the listener interface that queues up and defers dispatch - * of decoded events until flushed. - */ -class QueuedInputListener : public InputListenerInterface { -protected: - virtual ~QueuedInputListener(); - -public: - QueuedInputListener(const sp<InputListenerInterface>& innerListener); - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - void flush(); - -private: - sp<InputListenerInterface> mInnerListener; - Vector<NotifyArgs*> mArgsQueue; -}; - -} // namespace android - -#endif // _UI_INPUT_LISTENER_H diff --git a/widget/gonk/libui/InputManager.cpp b/widget/gonk/libui/InputManager.cpp deleted file mode 100644 index 91af056bf..000000000 --- a/widget/gonk/libui/InputManager.cpp +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputManager" - -//#define LOG_NDEBUG 0 - -#include "InputManager.h" - -#include "cutils_log.h" - -namespace android { - -InputManager::InputManager( - const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& readerPolicy, - const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { - mDispatcher = new InputDispatcher(dispatcherPolicy); - mReader = new InputReader(eventHub, readerPolicy, mDispatcher); - initialize(); -} - -InputManager::InputManager( - const sp<InputReaderInterface>& reader, - const sp<InputDispatcherInterface>& dispatcher) : - mReader(reader), - mDispatcher(dispatcher) { - initialize(); -} - -InputManager::~InputManager() { - stop(); -} - -void InputManager::initialize() { - mReaderThread = new InputReaderThread(mReader); - mDispatcherThread = new InputDispatcherThread(mDispatcher); -} - -status_t InputManager::start() { - status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); - if (result) { - ALOGE("Could not start InputDispatcher thread due to error %d.", result); - return result; - } - - result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); - if (result) { - ALOGE("Could not start InputReader thread due to error %d.", result); - - mDispatcherThread->requestExit(); - return result; - } - - return OK; -} - -status_t InputManager::stop() { - status_t result = mReaderThread->requestExitAndWait(); - if (result) { - ALOGW("Could not stop InputReader thread due to error %d.", result); - } - - result = mDispatcherThread->requestExitAndWait(); - if (result) { - ALOGW("Could not stop InputDispatcher thread due to error %d.", result); - } - - return OK; -} - -sp<InputReaderInterface> InputManager::getReader() { - return mReader; -} - -sp<InputDispatcherInterface> InputManager::getDispatcher() { - return mDispatcher; -} - -} // namespace android diff --git a/widget/gonk/libui/InputManager.h b/widget/gonk/libui/InputManager.h deleted file mode 100644 index 15a5176ec..000000000 --- a/widget/gonk/libui/InputManager.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_INPUT_MANAGER_H -#define _UI_INPUT_MANAGER_H - -/** - * Native input manager. - */ - -#include "EventHub.h" -#include "InputReader.h" -#include "InputDispatcher.h" - -#include "Input.h" -#include "InputTransport.h" -#include <utils/Errors.h> -#include <utils/Vector.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> - -namespace android { - -/* - * The input manager is the core of the system event processing. - * - * The input manager uses two threads. - * - * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events, - * applies policy, and posts messages to a queue managed by the DispatcherThread. - * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the - * queue and asynchronously dispatches them to applications. - * - * By design, the InputReaderThread class and InputDispatcherThread class do not share any - * internal state. Moreover, all communication is done one way from the InputReaderThread - * into the InputDispatcherThread and never the reverse. Both classes may interact with the - * InputDispatchPolicy, however. - * - * The InputManager class never makes any calls into Java itself. Instead, the - * InputDispatchPolicy is responsible for performing all external interactions with the - * system, including calling DVM services. - */ -class InputManagerInterface : public virtual RefBase { -protected: - InputManagerInterface() { } - virtual ~InputManagerInterface() { } - -public: - /* Starts the input manager threads. */ - virtual status_t start() = 0; - - /* Stops the input manager threads and waits for them to exit. */ - virtual status_t stop() = 0; - - /* Gets the input reader. */ - virtual sp<InputReaderInterface> getReader() = 0; - - /* Gets the input dispatcher. */ - virtual sp<InputDispatcherInterface> getDispatcher() = 0; -}; - -class InputManager : public InputManagerInterface { -protected: - virtual ~InputManager(); - -public: - InputManager( - const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& readerPolicy, - const sp<InputDispatcherPolicyInterface>& dispatcherPolicy); - - // (used for testing purposes) - InputManager( - const sp<InputReaderInterface>& reader, - const sp<InputDispatcherInterface>& dispatcher); - - virtual status_t start(); - virtual status_t stop(); - - virtual sp<InputReaderInterface> getReader(); - virtual sp<InputDispatcherInterface> getDispatcher(); - -private: - sp<InputReaderInterface> mReader; - sp<InputReaderThread> mReaderThread; - - sp<InputDispatcherInterface> mDispatcher; - sp<InputDispatcherThread> mDispatcherThread; - - void initialize(); -}; - -} // namespace android - -#endif // _UI_INPUT_MANAGER_H diff --git a/widget/gonk/libui/InputReader.cpp b/widget/gonk/libui/InputReader.cpp deleted file mode 100644 index 3699569aa..000000000 --- a/widget/gonk/libui/InputReader.cpp +++ /dev/null @@ -1,6510 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputReader" - -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -// Log debug messages for each raw event received from the EventHub. -#define DEBUG_RAW_EVENTS 0 - -// Log debug messages about touch screen filtering hacks. -#define DEBUG_HACKS 0 - -// Log debug messages about virtual key processing. -#define DEBUG_VIRTUAL_KEYS 0 - -// Log debug messages about pointers. -#define DEBUG_POINTERS 0 - -// Log debug messages about pointer assignment calculations. -#define DEBUG_POINTER_ASSIGNMENT 0 - -// Log debug messages about gesture detection. -#define DEBUG_GESTURES 0 - -// Log debug messages about the vibrator. -#define DEBUG_VIBRATOR 0 - -#include "InputReader.h" - -#include "Keyboard.h" -#include "VirtualKeyMap.h" - -#include <stddef.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <limits.h> -#include <math.h> - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " -#define INDENT5 " " - -namespace android { - -// --- Constants --- - -// Maximum number of slots supported when using the slot-based Multitouch Protocol B. -static const size_t MAX_SLOTS = 32; - -// --- Static Functions --- - -template<typename T> -inline static T abs(const T& value) { - return value < 0 ? - value : value; -} - -template<typename T> -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -template<typename T> -inline static void swap(T& a, T& b) { - T temp = a; - a = b; - b = temp; -} - -inline static float avg(float x, float y) { - return (x + y) / 2; -} - -inline static float distance(float x1, float y1, float x2, float y2) { - return hypotf(x1 - x2, y1 - y2); -} - -inline static int32_t signExtendNybble(int32_t value) { - return value >= 8 ? value - 16 : value; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, - const int32_t map[][4], size_t mapSize) { - if (orientation != DISPLAY_ORIENTATION_0) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][orientation]; - } - } - } - return value; -} - -static const int32_t keyCodeRotationMap[][4] = { - // key codes enumerated counter-clockwise with the original (unrotated) key first - // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, - { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, - { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, - { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, -}; -static const size_t keyCodeRotationMapSize = - sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); - -static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - return rotateValueUsingRotationMap(keyCode, orientation, - keyCodeRotationMap, keyCodeRotationMapSize); -} - -static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { - float temp; - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = *deltaX; - *deltaX = *deltaY; - *deltaY = -temp; - break; - - case DISPLAY_ORIENTATION_180: - *deltaX = -*deltaX; - *deltaY = -*deltaY; - break; - - case DISPLAY_ORIENTATION_270: - temp = *deltaX; - *deltaX = -*deltaY; - *deltaY = temp; - break; - } -} - -static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { - return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; -} - -// Returns true if the pointer should be reported as being down given the specified -// button states. This determines whether the event is reported as a touch event. -static bool isPointerDown(int32_t buttonState) { - return buttonState & - (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY - | AMOTION_EVENT_BUTTON_TERTIARY); -} - -static float calculateCommonVector(float a, float b) { - if (a > 0 && b > 0) { - return a < b ? a : b; - } else if (a < 0 && b < 0) { - return a > b ? a : b; - } else { - return 0; - } -} - -static void synthesizeButtonKey(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, - int32_t buttonState, int32_t keyCode) { - if ( - (action == AKEY_EVENT_ACTION_DOWN - && !(lastButtonState & buttonState) - && (currentButtonState & buttonState)) - || (action == AKEY_EVENT_ACTION_UP - && (lastButtonState & buttonState) - && !(currentButtonState & buttonState))) { - NotifyKeyArgs args(when, deviceId, source, policyFlags, - action, 0, keyCode, 0, context->getGlobalMetaState(), when); - context->getListener()->notifyKey(&args); - } -} - -static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { - synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); - synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); -} - - -// --- InputReaderConfiguration --- - -bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const { - const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay; - if (viewport.displayId >= 0) { - *outViewport = viewport; - return true; - } - return false; -} - -void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) { - DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay; - v = viewport; -} - - -// --- InputReader --- - -InputReader::InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener) : - mContext(this), mEventHub(eventHub), mPolicy(policy), - mGlobalMetaState(0), mGeneration(1), - mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), - mConfigurationChangesToRefresh(0) { - mQueuedListener = new QueuedInputListener(listener); - - { // acquire lock - AutoMutex _l(mLock); - - refreshConfigurationLocked(0); - updateGlobalMetaStateLocked(); - } // release lock -} - -InputReader::~InputReader() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } -} - -void InputReader::loopOnce() { - int32_t oldGeneration; - int32_t timeoutMillis; - bool inputDevicesChanged = false; - Vector<InputDeviceInfo> inputDevices; - { // acquire lock - AutoMutex _l(mLock); - - oldGeneration = mGeneration; - timeoutMillis = -1; - - uint32_t changes = mConfigurationChangesToRefresh; - if (changes) { - mConfigurationChangesToRefresh = 0; - timeoutMillis = 0; - refreshConfigurationLocked(changes); - } else if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); - } - } // release lock - - size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); - - { // acquire lock - AutoMutex _l(mLock); - mReaderIsAliveCondition.broadcast(); - - if (count) { - processEventsLocked(mEventBuffer, count); - } - - if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (now >= mNextTimeout) { -#if DEBUG_RAW_EVENTS - ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); -#endif - mNextTimeout = LLONG_MAX; - timeoutExpiredLocked(now); - } - } - - if (oldGeneration != mGeneration) { - inputDevicesChanged = true; - getInputDevicesLocked(inputDevices); - } - } // release lock - - // Send out a message that the describes the changed input devices. - if (inputDevicesChanged) { - mPolicy->notifyInputDevicesChanged(inputDevices); - } - - // Flush queued events out to the listener. - // This must happen outside of the lock because the listener could potentially call - // back into the InputReader's methods, such as getScanCodeState, or become blocked - // on another thread similarly waiting to acquire the InputReader lock thereby - // resulting in a deadlock. This situation is actually quite plausible because the - // listener is actually the input dispatcher, which calls into the window manager, - // which occasionally calls into the input reader. - mQueuedListener->flush(); -} - -void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { - for (const RawEvent* rawEvent = rawEvents; count;) { - int32_t type = rawEvent->type; - size_t batchSize = 1; - if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { - int32_t deviceId = rawEvent->deviceId; - while (batchSize < count) { - if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT - || rawEvent[batchSize].deviceId != deviceId) { - break; - } - batchSize += 1; - } -#if DEBUG_RAW_EVENTS - ALOGD("BatchSize: %d Count: %d", batchSize, count); -#endif - processEventsForDeviceLocked(deviceId, rawEvent, batchSize); - } else { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::DEVICE_REMOVED: - removeDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChangedLocked(rawEvent->when); - break; - default: - ALOG_ASSERT(false); // can't happen - break; - } - } - count -= batchSize; - rawEvent += batchSize; - } -} - -void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - return; - } - - InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - - InputDevice* device = createDeviceLocked(deviceId, identifier, classes); - device->configure(when, &mConfig, 0); - device->reset(when); - - if (device->isIgnored()) { - ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, - identifier.name.string()); - } else { - ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, - identifier.name.string(), device->getSources()); - } - - mDevices.add(deviceId, device); - bumpGenerationLocked(); -} - -void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { - InputDevice* device = NULL; - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); - return; - } - - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - bumpGenerationLocked(); - - if (device->isIgnored()) { - ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", - device->getId(), device->getName().string()); - } else { - ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", - device->getId(), device->getName().string(), device->getSources()); - } - - device->reset(when); - delete device; -} - -InputDevice* InputReader::createDeviceLocked(int32_t deviceId, - const InputDeviceIdentifier& identifier, uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), - identifier, classes); - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - device->setExternal(true); - } - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Vibrator-like devices. - if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - device->addMapper(new VibratorInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSource = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSource |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSource |= AINPUT_SOURCE_DPAD; - } - if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSource |= AINPUT_SOURCE_GAMEPAD; - } - - if (keyboardSource != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); - } - - // Cursor-like devices. - if (classes & INPUT_DEVICE_CLASS_CURSOR) { - device->addMapper(new CursorInputMapper(device)); - } - - // Touchscreens and touchpad devices. - if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - // Joystick-like devices. - if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - device->addMapper(new JoystickInputMapper(device)); - } - - return device; -} - -void InputReader::processEventsForDeviceLocked(int32_t deviceId, - const RawEvent* rawEvents, size_t count) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Discarding event for unknown deviceId %d.", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - //ALOGD("Discarding event for ignored deviceId %d.", deviceId); - return; - } - - device->process(rawEvents, count); -} - -void InputReader::timeoutExpiredLocked(nsecs_t when) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - device->timeoutExpired(when); - } - } -} - -void InputReader::handleConfigurationChangedLocked(nsecs_t when) { - // Reset global meta state because it depends on the list of all configured devices. - updateGlobalMetaStateLocked(); - - // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(when); - mQueuedListener->notifyConfigurationChanged(&args); -} - -void InputReader::refreshConfigurationLocked(uint32_t changes) { - mPolicy->getReaderConfiguration(&mConfig); - mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); - - if (changes) { - ALOGI("Reconfiguring input devices. changes=0x%08x", changes); - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { - mEventHub->requestReopenDevices(); - } else { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->configure(now, &mConfig, changes); - } - } - } -} - -void InputReader::updateGlobalMetaStateLocked() { - mGlobalMetaState = 0; - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - mGlobalMetaState |= device->getMetaState(); - } -} - -int32_t InputReader::getGlobalMetaStateLocked() { - return mGlobalMetaState; -} - -void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { - mDisableVirtualKeysTimeout = time; -} - -bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - if (now < mDisableVirtualKeysTimeout) { - ALOGI("Dropping virtual key from device %s because virtual keys are " - "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", - device->getName().string(), - (mDisableVirtualKeysTimeout - now) * 0.000001, - keyCode, scanCode); - return true; - } else { - return false; - } -} - -void InputReader::fadePointerLocked() { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->fadePointer(); - } -} - -void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { - if (when < mNextTimeout) { - mNextTimeout = when; - mEventHub->wake(); - } -} - -int32_t InputReader::bumpGenerationLocked() { - return ++mGeneration; -} - -void InputReader::getInputDevices(Vector<InputDeviceInfo>& outInputDevices) { - AutoMutex _l(mLock); - getInputDevicesLocked(outInputDevices); -} - -void InputReader::getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices) { - outInputDevices.clear(); - - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - outInputDevices.push(); - device->getDeviceInfo(&outInputDevices.editTop()); - } - } -} - -int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); -} - -int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); -} - -int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); -} - -int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. - int32_t currentResult = (device->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - } - return result; -} - -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - AutoMutex _l(mLock); - - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); -} - -bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } - return result; -} - -void InputReader::requestRefreshConfiguration(uint32_t changes) { - AutoMutex _l(mLock); - - if (changes) { - bool needWake = !mConfigurationChangesToRefresh; - mConfigurationChangesToRefresh |= changes; - - if (needWake) { - mEventHub->wake(); - } - } -} - -void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->cancelVibrate(token); - } -} - -void InputReader::dump(String8& dump) { - AutoMutex _l(mLock); - - mEventHub->dump(dump); - dump.append("\n"); - - dump.append("Input Reader State:\n"); - - for (size_t i = 0; i < mDevices.size(); i++) { - mDevices.valueAt(i)->dump(dump); - } - - dump.append(INDENT "Configuration:\n"); - dump.append(INDENT2 "ExcludedDeviceNames: ["); - for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { - if (i != 0) { - dump.append(", "); - } - dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); - } - dump.append("]\n"); - dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", - mConfig.virtualKeyQuietTime * 0.000001f); - - dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.pointerVelocityControlParameters.scale, - mConfig.pointerVelocityControlParameters.lowThreshold, - mConfig.pointerVelocityControlParameters.highThreshold, - mConfig.pointerVelocityControlParameters.acceleration); - - dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.wheelVelocityControlParameters.scale, - mConfig.wheelVelocityControlParameters.lowThreshold, - mConfig.wheelVelocityControlParameters.highThreshold, - mConfig.wheelVelocityControlParameters.acceleration); - - dump.appendFormat(INDENT2 "PointerGesture:\n"); - dump.appendFormat(INDENT3 "Enabled: %s\n", - toString(mConfig.pointerGesturesEnabled)); - dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", - mConfig.pointerGestureQuietInterval * 0.000001f); - dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", - mConfig.pointerGestureDragMinSwitchSpeed); - dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", - mConfig.pointerGestureTapInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", - mConfig.pointerGestureTapDragInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", - mConfig.pointerGestureTapSlop); - dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", - mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); - dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n", - mConfig.pointerGestureMultitouchMinDistance); - dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", - mConfig.pointerGestureSwipeTransitionAngleCosine); - dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", - mConfig.pointerGestureSwipeMaxWidthRatio); - dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", - mConfig.pointerGestureMovementSpeedRatio); - dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", - mConfig.pointerGestureZoomSpeedRatio); -} - -void InputReader::monitor() { - // Acquire and release the lock to ensure that the reader has not deadlocked. - mLock.lock(); - mEventHub->wake(); - mReaderIsAliveCondition.wait(mLock); - mLock.unlock(); - - // Check the EventHub - mEventHub->monitor(); -} - - -// --- InputReader::ContextImpl --- - -InputReader::ContextImpl::ContextImpl(InputReader* reader) : - mReader(reader) { -} - -void InputReader::ContextImpl::updateGlobalMetaState() { - // lock is already held by the input loop - mReader->updateGlobalMetaStateLocked(); -} - -int32_t InputReader::ContextImpl::getGlobalMetaState() { - // lock is already held by the input loop - return mReader->getGlobalMetaStateLocked(); -} - -void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { - // lock is already held by the input loop - mReader->disableVirtualKeysUntilLocked(time); -} - -bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - // lock is already held by the input loop - return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); -} - -void InputReader::ContextImpl::fadePointer() { - // lock is already held by the input loop - mReader->fadePointerLocked(); -} - -void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { - // lock is already held by the input loop - mReader->requestTimeoutAtTimeLocked(when); -} - -int32_t InputReader::ContextImpl::bumpGeneration() { - // lock is already held by the input loop - return mReader->bumpGenerationLocked(); -} - -InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { - return mReader->mPolicy.get(); -} - -InputListenerInterface* InputReader::ContextImpl::getListener() { - return mReader->mQueuedListener.get(); -} - -EventHubInterface* InputReader::ContextImpl::getEventHub() { - return mReader->mEventHub.get(); -} - - -// --- InputReaderThread --- - -InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) : - Thread(/*canCallJava*/ true), mReader(reader) { -} - -InputReaderThread::~InputReaderThread() { -} - -bool InputReaderThread::threadLoop() { - mReader->loopOnce(); - return true; -} - - -// --- InputDevice --- - -InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - const InputDeviceIdentifier& identifier, uint32_t classes) : - mContext(context), mId(id), mGeneration(generation), - mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mDropUntilNextSync(false) { -} - -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} - -void InputDevice::dump(String8& dump) { - InputDeviceInfo deviceInfo; - getDeviceInfo(& deviceInfo); - - dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), - deviceInfo.getDisplayName().string()); - dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); - dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); - dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - - const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); - if (!ranges.isEmpty()) { - dump.append(INDENT2 "Motion Ranges:\n"); - for (size_t i = 0; i < ranges.size(); i++) { - const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); - const char* label = getAxisLabel(range.axis); - char name[32]; - if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; - } else { - snprintf(name, sizeof(name), "%d", range.axis); - } - dump.appendFormat(INDENT3 "%s: source=0x%08x, " - "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", - name, range.source, range.min, range.max, range.flat, range.fuzz, - range.resolution); - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } -} - -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.add(mapper); -} - -void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { - mSources = 0; - - if (!isIgnored()) { - if (!changes) { // first time only - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - sp<KeyCharacterMap> keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); - if (mAlias != alias) { - mAlias = alias; - bumpGeneration(); - } - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->configure(when, config, changes); - mSources |= mapper->getSources(); - } - } -} - -void InputDevice::reset(nsecs_t when) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->reset(when); - } - - mContext->updateGlobalMetaState(); - - notifyReset(when); -} - -void InputDevice::process(const RawEvent* rawEvents, size_t count) { - // Process all of the events in order for each mapper. - // We cannot simply ask each mapper to process them in bulk because mappers may - // have side-effects that must be interleaved. For example, joystick movement events and - // gamepad button presses are handled by different mappers but they should be dispatched - // in the order received. - size_t numMappers = mMappers.size(); - for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { -#if DEBUG_RAW_EVENTS - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld", - rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, - rawEvent->when); -#endif - - if (mDropUntilNextSync) { - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - mDropUntilNextSync = false; -#if DEBUG_RAW_EVENTS - ALOGD("Recovered from input event buffer overrun."); -#endif - } else { -#if DEBUG_RAW_EVENTS - ALOGD("Dropped input event while waiting for next input sync."); -#endif - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { - ALOGI("Detected input event buffer overrun for device %s.", getName().string()); - mDropUntilNextSync = true; - reset(rawEvent->when); - } else { - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); - } - } - } -} - -void InputDevice::timeoutExpired(nsecs_t when) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->timeoutExpired(when); - } -} - -void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mGeneration, mIdentifier, mAlias, mIsExternal); - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->populateDeviceInfo(outDeviceInfo); - } -} - -int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); -} - -int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); -} - -int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getState(sourceMask, switchCode, & InputMapper::getSwitchState); -} - -int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - return result; -} - -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - return result; -} - -void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputDevice::cancelVibrate(int32_t token) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->cancelVibrate(token); - } -} - -int32_t InputDevice::getMetaState() { - int32_t result = 0; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - result |= mapper->getMetaState(); - } - return result; -} - -void InputDevice::fadePointer() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->fadePointer(); - } -} - -void InputDevice::bumpGeneration() { - mGeneration = mContext->bumpGeneration(); -} - -void InputDevice::notifyReset(nsecs_t when) { - NotifyDeviceResetArgs args(when, mId); - mContext->getListener()->notifyDeviceReset(&args); -} - - -// --- CursorButtonAccumulator --- - -CursorButtonAccumulator::CursorButtonAccumulator() { - clearButtons(); -} - -void CursorButtonAccumulator::reset(InputDevice* device) { - mBtnLeft = device->isKeyPressed(BTN_LEFT); - mBtnRight = device->isKeyPressed(BTN_RIGHT); - mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); - mBtnBack = device->isKeyPressed(BTN_BACK); - mBtnSide = device->isKeyPressed(BTN_SIDE); - mBtnForward = device->isKeyPressed(BTN_FORWARD); - mBtnExtra = device->isKeyPressed(BTN_EXTRA); - mBtnTask = device->isKeyPressed(BTN_TASK); -} - -void CursorButtonAccumulator::clearButtons() { - mBtnLeft = 0; - mBtnRight = 0; - mBtnMiddle = 0; - mBtnBack = 0; - mBtnSide = 0; - mBtnForward = 0; - mBtnExtra = 0; - mBtnTask = 0; -} - -void CursorButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_LEFT: - mBtnLeft = rawEvent->value; - break; - case BTN_RIGHT: - mBtnRight = rawEvent->value; - break; - case BTN_MIDDLE: - mBtnMiddle = rawEvent->value; - break; - case BTN_BACK: - mBtnBack = rawEvent->value; - break; - case BTN_SIDE: - mBtnSide = rawEvent->value; - break; - case BTN_FORWARD: - mBtnForward = rawEvent->value; - break; - case BTN_EXTRA: - mBtnExtra = rawEvent->value; - break; - case BTN_TASK: - mBtnTask = rawEvent->value; - break; - } - } -} - -uint32_t CursorButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnLeft) { - result |= AMOTION_EVENT_BUTTON_PRIMARY; - } - if (mBtnRight) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnMiddle) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - if (mBtnBack || mBtnSide) { - result |= AMOTION_EVENT_BUTTON_BACK; - } - if (mBtnForward || mBtnExtra) { - result |= AMOTION_EVENT_BUTTON_FORWARD; - } - return result; -} - - -// --- CursorMotionAccumulator --- - -CursorMotionAccumulator::CursorMotionAccumulator() { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::clearRelativeAxes() { - mRelX = 0; - mRelY = 0; -} - -void CursorMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_X: - mRelX = rawEvent->value; - break; - case REL_Y: - mRelY = rawEvent->value; - break; - } - } -} - -void CursorMotionAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- CursorScrollAccumulator --- - -CursorScrollAccumulator::CursorScrollAccumulator() : - mHaveRelWheel(false), mHaveRelHWheel(false) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); -} - -void CursorScrollAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::clearRelativeAxes() { - mRelWheel = 0; - mRelHWheel = 0; -} - -void CursorScrollAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_WHEEL: - mRelWheel = rawEvent->value; - break; - case REL_HWHEEL: - mRelHWheel = rawEvent->value; - break; - } - } -} - -void CursorScrollAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- TouchButtonAccumulator --- - -TouchButtonAccumulator::TouchButtonAccumulator() : - mHaveBtnTouch(false), mHaveStylus(false) { - clearButtons(); -} - -void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->hasKey(BTN_TOUCH); - mHaveStylus = device->hasKey(BTN_TOOL_PEN) - || device->hasKey(BTN_TOOL_RUBBER) - || device->hasKey(BTN_TOOL_BRUSH) - || device->hasKey(BTN_TOOL_PENCIL) - || device->hasKey(BTN_TOOL_AIRBRUSH); -} - -void TouchButtonAccumulator::reset(InputDevice* device) { - mBtnTouch = device->isKeyPressed(BTN_TOUCH); - mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); - mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); - mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); - mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); - mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); - mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); - mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); - mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); - mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); - mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); - mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); - mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); -} - -void TouchButtonAccumulator::clearButtons() { - mBtnTouch = 0; - mBtnStylus = 0; - mBtnStylus2 = 0; - mBtnToolFinger = 0; - mBtnToolPen = 0; - mBtnToolRubber = 0; - mBtnToolBrush = 0; - mBtnToolPencil = 0; - mBtnToolAirbrush = 0; - mBtnToolMouse = 0; - mBtnToolLens = 0; - mBtnToolDoubleTap = 0; - mBtnToolTripleTap = 0; - mBtnToolQuadTap = 0; -} - -void TouchButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_TOUCH: - mBtnTouch = rawEvent->value; - break; - case BTN_STYLUS: - mBtnStylus = rawEvent->value; - break; - case BTN_STYLUS2: - mBtnStylus2 = rawEvent->value; - break; - case BTN_TOOL_FINGER: - mBtnToolFinger = rawEvent->value; - break; - case BTN_TOOL_PEN: - mBtnToolPen = rawEvent->value; - break; - case BTN_TOOL_RUBBER: - mBtnToolRubber = rawEvent->value; - break; - case BTN_TOOL_BRUSH: - mBtnToolBrush = rawEvent->value; - break; - case BTN_TOOL_PENCIL: - mBtnToolPencil = rawEvent->value; - break; - case BTN_TOOL_AIRBRUSH: - mBtnToolAirbrush = rawEvent->value; - break; - case BTN_TOOL_MOUSE: - mBtnToolMouse = rawEvent->value; - break; - case BTN_TOOL_LENS: - mBtnToolLens = rawEvent->value; - break; - case BTN_TOOL_DOUBLETAP: - mBtnToolDoubleTap = rawEvent->value; - break; - case BTN_TOOL_TRIPLETAP: - mBtnToolTripleTap = rawEvent->value; - break; - case BTN_TOOL_QUADTAP: - mBtnToolQuadTap = rawEvent->value; - break; - } - } -} - -uint32_t TouchButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - return result; -} - -int32_t TouchButtonAccumulator::getToolType() const { - if (mBtnToolMouse || mBtnToolLens) { - return AMOTION_EVENT_TOOL_TYPE_MOUSE; - } - if (mBtnToolRubber) { - return AMOTION_EVENT_TOOL_TYPE_ERASER; - } - if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { - return AMOTION_EVENT_TOOL_TYPE_FINGER; - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -bool TouchButtonAccumulator::isToolActive() const { - return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber - || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush - || mBtnToolMouse || mBtnToolLens - || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; -} - -bool TouchButtonAccumulator::isHovering() const { - return mHaveBtnTouch && !mBtnTouch; -} - -bool TouchButtonAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- RawPointerAxes --- - -RawPointerAxes::RawPointerAxes() { - clear(); -} - -void RawPointerAxes::clear() { - x.clear(); - y.clear(); - pressure.clear(); - touchMajor.clear(); - touchMinor.clear(); - toolMajor.clear(); - toolMinor.clear(); - orientation.clear(); - distance.clear(); - tiltX.clear(); - tiltY.clear(); - trackingId.clear(); - slot.clear(); -} - - -// --- RawPointerData --- - -RawPointerData::RawPointerData() { - clear(); -} - -void RawPointerData::clear() { - pointerCount = 0; - clearIdBits(); -} - -void RawPointerData::copyFrom(const RawPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointers[i] = other.pointers[i]; - - int id = pointers[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - -void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { - float x = 0, y = 0; - uint32_t count = touchingIdBits.count(); - if (count) { - for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const Pointer& pointer = pointerForId(id); - x += pointer.x; - y += pointer.y; - } - x /= count; - y /= count; - } - *outX = x; - *outY = y; -} - - -// --- CookedPointerData --- - -CookedPointerData::CookedPointerData() { - clear(); -} - -void CookedPointerData::clear() { - pointerCount = 0; - hoveringIdBits.clear(); - touchingIdBits.clear(); -} - -void CookedPointerData::copyFrom(const CookedPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - - int id = pointerProperties[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - - -// --- SingleTouchMotionAccumulator --- - -SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { - clearAbsoluteAxes(); -} - -void SingleTouchMotionAccumulator::reset(InputDevice* device) { - mAbsX = device->getAbsoluteAxisValue(ABS_X); - mAbsY = device->getAbsoluteAxisValue(ABS_Y); - mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); - mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); - mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); - mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); - mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); -} - -void SingleTouchMotionAccumulator::clearAbsoluteAxes() { - mAbsX = 0; - mAbsY = 0; - mAbsPressure = 0; - mAbsToolWidth = 0; - mAbsDistance = 0; - mAbsTiltX = 0; - mAbsTiltY = 0; -} - -void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - switch (rawEvent->code) { - case ABS_X: - mAbsX = rawEvent->value; - break; - case ABS_Y: - mAbsY = rawEvent->value; - break; - case ABS_PRESSURE: - mAbsPressure = rawEvent->value; - break; - case ABS_TOOL_WIDTH: - mAbsToolWidth = rawEvent->value; - break; - case ABS_DISTANCE: - mAbsDistance = rawEvent->value; - break; - case ABS_TILT_X: - mAbsTiltX = rawEvent->value; - break; - case ABS_TILT_Y: - mAbsTiltY = rawEvent->value; - break; - } - } -} - - -// --- MultiTouchMotionAccumulator --- - -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : - mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false), - mHaveStylus(false) { -} - -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - -void MultiTouchMotionAccumulator::configure(InputDevice* device, - size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; - mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - - delete[] mSlots; - mSlots = new Slot[slotCount]; -} - -void MultiTouchMotionAccumulator::reset(InputDevice* device) { - // Unfortunately there is no way to read the initial contents of the slots. - // So when we reset the accumulator, we must assume they are all zeroes. - if (mUsingSlotsProtocol) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), - ABS_MT_SLOT, &initialSlot); - if (status) { - ALOGD("Could not retrieve current multitouch slot index. status=%d", status); - initialSlot = -1; - } - clearSlots(initialSlot); - } else { - clearSlots(-1); - } -} - -void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } - } - mCurrentSlot = initialSlot; -} - -void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { -#if DEBUG_POINTERS - bool newSlot = false; -#endif - if (mUsingSlotsProtocol) { - if (rawEvent->code == ABS_MT_SLOT) { - mCurrentSlot = rawEvent->value; -#if DEBUG_POINTERS - newSlot = true; -#endif - } - } else if (mCurrentSlot < 0) { - mCurrentSlot = 0; - } - - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { -#if DEBUG_POINTERS - if (newSlot) { - ALOGW("MultiTouch device emitted invalid slot index %d but it " - "should be between 0 and %d; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); - } -#endif - } else { - Slot* slot = &mSlots[mCurrentSlot]; - - switch (rawEvent->code) { - case ABS_MT_POSITION_X: - slot->mInUse = true; - slot->mAbsMTPositionX = rawEvent->value; - break; - case ABS_MT_POSITION_Y: - slot->mInUse = true; - slot->mAbsMTPositionY = rawEvent->value; - break; - case ABS_MT_TOUCH_MAJOR: - slot->mInUse = true; - slot->mAbsMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - slot->mInUse = true; - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; - break; - case ABS_MT_WIDTH_MAJOR: - slot->mInUse = true; - slot->mAbsMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - slot->mInUse = true; - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; - break; - case ABS_MT_ORIENTATION: - slot->mInUse = true; - slot->mAbsMTOrientation = rawEvent->value; - break; - case ABS_MT_TRACKING_ID: - if (mUsingSlotsProtocol && rawEvent->value < 0) { - // The slot is no longer in use but it retains its previous contents, - // which may be reused for subsequent touches. - slot->mInUse = false; - } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; - } - break; - case ABS_MT_PRESSURE: - slot->mInUse = true; - slot->mAbsMTPressure = rawEvent->value; - break; - case ABS_MT_DISTANCE: - slot->mInUse = true; - slot->mAbsMTDistance = rawEvent->value; - break; - case ABS_MT_TOOL_TYPE: - slot->mInUse = true; - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; - break; - } - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - mCurrentSlot += 1; - } -} - -void MultiTouchMotionAccumulator::finishSync() { - if (!mUsingSlotsProtocol) { - clearSlots(-1); - } -} - -bool MultiTouchMotionAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- MultiTouchMotionAccumulator::Slot --- - -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - -int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { - if (mHaveAbsMTToolType) { - switch (mAbsMTToolType) { - case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; - case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - - -// --- InputMapper --- - -InputMapper::InputMapper(InputDevice* device) : - mDevice(device), mContext(device->getContext()) { -} - -InputMapper::~InputMapper() { -} - -void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { - info->addSource(getSources()); -} - -void InputMapper::dump(String8& dump) { -} - -void InputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { -} - -void InputMapper::reset(nsecs_t when) { -} - -void InputMapper::timeoutExpired(nsecs_t when) { -} - -int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return AKEY_STATE_UNKNOWN; -} - -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return false; -} - -void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -} - -void InputMapper::cancelVibrate(int32_t token) { -} - -int32_t InputMapper::getMetaState() { - return 0; -} - -void InputMapper::fadePointer() { -} - -status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { - return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); -} - -void InputMapper::bumpGeneration() { - mDevice->bumpGeneration(); -} - -void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, - const RawAbsoluteAxisInfo& axis, const char* name) { - if (axis.valid) { - dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", - name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); - } else { - dump.appendFormat(INDENT4 "%s: unknown range\n", name); - } -} - - -// --- SwitchInputMapper --- - -SwitchInputMapper::SwitchInputMapper(InputDevice* device) : - InputMapper(device), mUpdatedSwitchValues(0), mUpdatedSwitchMask(0) { -} - -SwitchInputMapper::~SwitchInputMapper() { -} - -uint32_t SwitchInputMapper::getSources() { - return AINPUT_SOURCE_SWITCH; -} - -void SwitchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_SW: - processSwitch(rawEvent->code, rawEvent->value); - break; - - case EV_SYN: - if (rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } - } -} - -void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { - if (switchCode >= 0 && switchCode < 32) { - if (switchValue) { - mUpdatedSwitchValues |= 1 << switchCode; - } - mUpdatedSwitchMask |= 1 << switchCode; - } -} - -void SwitchInputMapper::sync(nsecs_t when) { - if (mUpdatedSwitchMask) { - NotifySwitchArgs args(when, 0, mUpdatedSwitchValues, mUpdatedSwitchMask); - getListener()->notifySwitch(&args); - - mUpdatedSwitchValues = 0; - mUpdatedSwitchMask = 0; - } -} - -int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); -} - - -// --- VibratorInputMapper --- - -VibratorInputMapper::VibratorInputMapper(InputDevice* device) : - InputMapper(device), mVibrating(false) { -} - -VibratorInputMapper::~VibratorInputMapper() { -} - -uint32_t VibratorInputMapper::getSources() { - return 0; -} - -void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setVibrator(true); -} - -void VibratorInputMapper::process(const RawEvent* rawEvent) { - // TODO: Handle FF_STATUS, although it does not seem to be widely supported. -} - -void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -#if DEBUG_VIBRATOR - String8 patternStr; - for (size_t i = 0; i < patternSize; i++) { - if (i != 0) { - patternStr.append(", "); - } - patternStr.appendFormat("%lld", pattern[i]); - } - ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d", - getDeviceId(), patternStr.string(), repeat, token); -#endif - - mVibrating = true; - memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); - mPatternSize = patternSize; - mRepeat = repeat; - mToken = token; - mIndex = -1; - - nextStep(); -} - -void VibratorInputMapper::cancelVibrate(int32_t token) { -#if DEBUG_VIBRATOR - ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); -#endif - - if (mVibrating && mToken == token) { - stopVibrating(); - } -} - -void VibratorInputMapper::timeoutExpired(nsecs_t when) { - if (mVibrating) { - if (when >= mNextStepTime) { - nextStep(); - } else { - getContext()->requestTimeoutAtTime(mNextStepTime); - } - } -} - -void VibratorInputMapper::nextStep() { - mIndex += 1; - if (size_t(mIndex) >= mPatternSize) { - if (mRepeat < 0) { - // We are done. - stopVibrating(); - return; - } - mIndex = mRepeat; - } - - bool vibratorOn = mIndex & 1; - nsecs_t duration = mPattern[mIndex]; - if (vibratorOn) { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld", - getDeviceId(), duration); -#endif - getEventHub()->vibrate(getDeviceId(), duration); - } else { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); - } - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - mNextStepTime = now + duration; - getContext()->requestTimeoutAtTime(mNextStepTime); -#if DEBUG_VIBRATOR - ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); -#endif -} - -void VibratorInputMapper::stopVibrating() { - mVibrating = false; -#if DEBUG_VIBRATOR - ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); -} - -void VibratorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Vibrator Input Mapper:\n"); - dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating)); -} - - -// --- KeyboardInputMapper --- - -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, - uint32_t source, int32_t keyboardType) : - InputMapper(device), mSource(source), - mKeyboardType(keyboardType) { -} - -KeyboardInputMapper::~KeyboardInputMapper() { -} - -uint32_t KeyboardInputMapper::getSources() { - return mSource; -} - -void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setKeyboardType(mKeyboardType); - info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); -} - -void KeyboardInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Keyboard Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size()); - dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); -} - - -void KeyboardInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - DisplayViewport v; - if (config->getDisplayInfo(false /*external*/, &v)) { - mOrientation = v.orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } -} - -void KeyboardInputMapper::configureParameters() { - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void KeyboardInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void KeyboardInputMapper::reset(nsecs_t when) { - mMetaState = AMETA_NONE; - mDownTime = 0; - mKeyDowns.clear(); - mCurrentHidUsage = 0; - - resetLedState(); - - InputMapper::reset(when); -} - -void KeyboardInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: { - int32_t scanCode = rawEvent->code; - int32_t usageCode = mCurrentHidUsage; - mCurrentHidUsage = 0; - - if (isKeyboardOrGamepadKey(scanCode)) { - int32_t keyCode; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) { - keyCode = AKEYCODE_UNKNOWN; - flags = 0; - } - processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags); - } - break; - } - case EV_MSC: { - if (rawEvent->code == MSC_SCAN) { - mCurrentHidUsage = rawEvent->value; - } - break; - } - case EV_SYN: { - if (rawEvent->code == SYN_REPORT) { - mCurrentHidUsage = 0; - } - } - } -} - -bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { - return scanCode < BTN_MOUSE - || scanCode >= KEY_OK - || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) - || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); -} - -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, - int32_t scanCode, uint32_t policyFlags) { - - if (down) { - // Rotate key codes according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - keyCode = rotateKeyCode(keyCode, mOrientation); - } - - // Add key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; - } else { - // key down - if ((policyFlags & POLICY_FLAG_VIRTUAL) - && mContext->shouldDropVirtualKey(when, - getDevice(), keyCode, scanCode)) { - return; - } - - mKeyDowns.push(); - KeyDown& keyDown = mKeyDowns.editTop(); - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; - } - - mDownTime = when; - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; - mKeyDowns.removeAt(size_t(keyDownIndex)); - } else { - // key was not actually down - ALOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().string(), keyCode, scanCode); - return; - } - } - - bool metaStateChanged = false; - int32_t oldMetaState = mMetaState; - int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); - if (oldMetaState != newMetaState) { - mMetaState = newMetaState; - metaStateChanged = true; - updateLedState(false); - } - - nsecs_t downTime = mDownTime; - - // Key down on external an keyboard should wake the device. - // We don't do this for internal keyboards to prevent them from waking up in your pocket. - // For internal keyboards, the key layout file should specify the policy flags for - // each wake key individually. - // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal() - && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - - if (metaStateChanged) { - getContext()->updateGlobalMetaState(); - } - - if (down && !isMetaKey(keyCode)) { - getContext()->fadePointer(); - } - - NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); - getListener()->notifyKey(&args); -} - -ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { - size_t n = mKeyDowns.size(); - for (size_t i = 0; i < n; i++) { - if (mKeyDowns[i].scanCode == scanCode) { - return i; - } - } - return -1; -} - -int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); -} - -int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); -} - -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); -} - -int32_t KeyboardInputMapper::getMetaState() { - return mMetaState; -} - -void KeyboardInputMapper::resetLedState() { - initializeLedState(mCapsLockLedState, LED_CAPSL); - initializeLedState(mNumLockLedState, LED_NUML); - initializeLedState(mScrollLockLedState, LED_SCROLLL); - - updateLedState(true); -} - -void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; -} - -void KeyboardInputMapper::updateLedState(bool reset) { - updateLedStateForModifier(mCapsLockLedState, LED_CAPSL, - AMETA_CAPS_LOCK_ON, reset); - updateLedStateForModifier(mNumLockLedState, LED_NUML, - AMETA_NUM_LOCK_ON, reset); - updateLedStateForModifier(mScrollLockLedState, LED_SCROLLL, - AMETA_SCROLL_LOCK_ON, reset); -} - -void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, - int32_t led, int32_t modifier, bool reset) { - if (ledState.avail) { - bool desiredState = (mMetaState & modifier) != 0; - if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); - ledState.on = desiredState; - } - } -} - - -// --- CursorInputMapper --- - -CursorInputMapper::CursorInputMapper(InputDevice* device) : - InputMapper(device) { -} - -CursorInputMapper::~CursorInputMapper() { -} - -uint32_t CursorInputMapper::getSources() { - return mSource; -} - -void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mParameters.mode == Parameters::MODE_POINTER) { - float minX, minY, maxX, maxY; - if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); - } - } else { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); - } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } -} - -void CursorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Cursor Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT3 "HaveVWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeVWheel())); - dump.appendFormat(INDENT3 "HaveHWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeHWheel())); - dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); - dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState); - dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); -} - -void CursorInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - mCursorScrollAccumulator.configure(getDevice()); - - // Configure basic parameters. - configureParameters(); - - // Configure device mode. - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - mSource = AINPUT_SOURCE_MOUSE; - mXPrecision = 1.0f; - mYPrecision = 1.0f; - mXScale = 1.0f; - mYScale = 1.0f; - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - break; - case Parameters::MODE_NAVIGATION: - mSource = AINPUT_SOURCE_TRACKBALL; - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - break; - } - - mVWheelScale = 1.0f; - mHWheelScale = 1.0f; - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - DisplayViewport v; - if (config->getDisplayInfo(false /*external*/, &v)) { - mOrientation = v.orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - bumpGeneration(); - } -} - -void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::MODE_POINTER; - String8 cursorModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { - if (cursorModeString == "navigation") { - mParameters.mode = Parameters::MODE_NAVIGATION; - } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); - } - } - - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void CursorInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - dump.append(INDENT4 "Mode: pointer\n"); - break; - case Parameters::MODE_NAVIGATION: - dump.append(INDENT4 "Mode: navigation\n"); - break; - default: - ALOG_ASSERT(false); - } - - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void CursorInputMapper::reset(nsecs_t when) { - mButtonState = 0; - mDownTime = 0; - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCursorButtonAccumulator.reset(getDevice()); - mCursorMotionAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void CursorInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorMotionAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void CursorInputMapper::sync(nsecs_t when) { - int32_t lastButtonState = mButtonState; - int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); - mButtonState = currentButtonState; - - bool wasDown = isPointerDown(lastButtonState); - bool down = isPointerDown(currentButtonState); - bool downChanged; - if (!wasDown && down) { - mDownTime = when; - downChanged = true; - } else if (wasDown && !down) { - downChanged = true; - } else { - downChanged = false; - } - nsecs_t downTime = mDownTime; - bool buttonsChanged = currentButtonState != lastButtonState; - bool buttonsPressed = currentButtonState & ~lastButtonState; - - float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; - float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; - bool moved = deltaX != 0 || deltaY != 0; - - // Rotate delta according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay - && (deltaX != 0.0f || deltaY != 0.0f)) { - rotateDelta(mOrientation, &deltaX, &deltaY); - } - - // Move the pointer. - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); - float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); - bool scrolled = vscroll != 0 || hscroll != 0; - - mWheelYVelocityControl.move(when, NULL, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, NULL); - - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - int32_t displayId; - if (mPointerController != NULL) { - if (moved || scrolled || buttonsChanged) { - mPointerController->setPresentation( - PointerControllerInterface::PRESENTATION_POINTER); - - if (moved) { - mPointerController->move(deltaX, deltaY); - } - - if (buttonsChanged) { - mPointerController->setButtonState(currentButtonState); - } - - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - displayId = ADISPLAY_ID_DEFAULT; - } else { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); - displayId = ADISPLAY_ID_NONE; - } - - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - - // Moving an external trackball or mouse should wake the device. - // We don't do this for internal cursor devices to prevent them from waking up - // the device in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - - // Synthesize key down from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, lastButtonState, currentButtonState); - - // Send motion event. - if (downChanged || moved || scrolled || buttonsChanged) { - int32_t metaState = mContext->getGlobalMetaState(); - int32_t motionEventAction; - if (downChanged) { - motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else if (down || mPointerController == NULL) { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } else { - motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; - } - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - motionEventAction, 0, metaState, currentButtonState, 0, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&args); - - // Send hover move after UP to tell the application that the mouse is hovering now. - if (motionEventAction == AMOTION_EVENT_ACTION_UP - && mPointerController != NULL) { - NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&hoverArgs); - } - - // Send scroll events. - if (scrolled) { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&scrollArgs); - } - } - - // Synthesize key up from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, lastButtonState, currentButtonState); - - mCursorMotionAccumulator.finishSync(); - mCursorScrollAccumulator.finishSync(); -} - -int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); - } else { - return AKEY_STATE_UNKNOWN; - } -} - -void CursorInputMapper::fadePointer() { - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - - -// --- TouchInputMapper --- - -TouchInputMapper::TouchInputMapper(InputDevice* device) : - InputMapper(device), - mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), - mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0), - mSurfaceOrientation(DISPLAY_ORIENTATION_0) { -} - -TouchInputMapper::~TouchInputMapper() { -} - -uint32_t TouchInputMapper::getSources() { - return mSource; -} - -void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mDeviceMode != DEVICE_MODE_DISABLED) { - info->addMotionRange(mOrientedRanges.x); - info->addMotionRange(mOrientedRanges.y); - info->addMotionRange(mOrientedRanges.pressure); - - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); - } - - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); - } - - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); - } - - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); - } - - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); - } - - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); - } - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; - const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - } - } -} - -void TouchInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Touch Input Mapper:\n"); - dumpParameters(dump); - dumpVirtualKeys(dump); - dumpRawPointerAxes(dump); - dumpCalibration(dump); - dumpSurface(dump); - - dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); - dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate); - dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); - dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale); - dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale); - dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); - dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); - dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); - dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); - dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); - dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); - dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); - - dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " - "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " - "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " - "toolType=%d, isHovering=%s\n", i, - pointer.id, pointer.x, pointer.y, pointer.pressure, - pointer.touchMajor, pointer.touchMinor, - pointer.toolMajor, pointer.toolMinor, - pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, - pointer.toolType, toString(pointer.isHovering)); - } - - dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " - "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " - "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " - "toolType=%d, isHovering=%s\n", i, - pointerProperties.id, - pointerCoords.getX(), - pointerCoords.getY(), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), - pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); - } - - if (mDeviceMode == DEVICE_MODE_POINTER) { - dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); - dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", - mPointerXMovementScale); - dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", - mPointerYMovementScale); - dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", - mPointerXZoomScale); - dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", - mPointerYZoomScale); - dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", - mPointerGestureMaxSwipeWidth); - } -} - -void TouchInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - mConfig = *config; - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - - // Configure common accumulators. - mCursorScrollAccumulator.configure(getDevice()); - mTouchButtonAccumulator.configure(getDevice()); - - // Configure absolute axis information. - configureRawPointerAxes(); - - // Prepare input device calibration. - parseCalibration(); - resolveCalibration(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - // Update pointer speed. - mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - } - - bool resetNeeded = false; - if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO - | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { - // Configure device sources, surface dimensions, orientation and - // scaling factors. - configureSurface(when, &resetNeeded); - } - - if (changes && resetNeeded) { - // Send reset, unless this is the first time the device has been configured, - // in which case the reader will call reset itself after all mappers are ready. - getDevice()->notifyReset(when); - } -} - -void TouchInputMapper::configureParameters() { - // Use the pointer presentation mode for devices that do not support distinct - // multitouch. The spot-based presentation relies on being able to accurately - // locate two or more fingers on the touch pad. - mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) - ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS; - - String8 gestureModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), - gestureModeString)) { - if (gestureModeString == "pointer") { - mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER; - } else if (gestureModeString == "spots") { - mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS; - } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); - } - } - - if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { - // The device is a touch screen. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { - // The device is a pointing device like a track pad. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) - || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { - // The device is a cursor device with a touch pad attached. - // By default don't use the touch pad to move the pointer. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else { - // The device is a touch pad of unknown purpose. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } - - String8 deviceTypeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { - if (deviceTypeString == "touchScreen") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else if (deviceTypeString == "touchNavigation") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; - } else if (deviceTypeString == "pointer") { - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); - } - } - - mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - mParameters.associatedDisplayIsExternal = false; - if (mParameters.orientationAware - || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - mParameters.hasAssociatedDisplay = true; - mParameters.associatedDisplayIsExternal = - mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && getDevice()->isExternal(); - } -} - -void TouchInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - - switch (mParameters.gestureMode) { - case Parameters::GESTURE_MODE_POINTER: - dump.append(INDENT4 "GestureMode: pointer\n"); - break; - case Parameters::GESTURE_MODE_SPOTS: - dump.append(INDENT4 "GestureMode: spots\n"); - break; - default: - assert(false); - } - - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump.append(INDENT4 "DeviceType: touchScreen\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump.append(INDENT4 "DeviceType: touchPad\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: - dump.append(INDENT4 "DeviceType: touchNavigation\n"); - break; - case Parameters::DEVICE_TYPE_POINTER: - dump.append(INDENT4 "DeviceType: pointer\n"); - break; - default: - ALOG_ASSERT(false); - } - - dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n", - toString(mParameters.hasAssociatedDisplay), - toString(mParameters.associatedDisplayIsExternal)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void TouchInputMapper::configureRawPointerAxes() { - mRawPointerAxes.clear(); -} - -void TouchInputMapper::dumpRawPointerAxes(String8& dump) { - dump.append(INDENT3 "Raw Touch Axes:\n"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); -} - -void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { - int32_t oldDeviceMode = mDeviceMode; - - // Determine device mode. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER - && mConfig.pointerGesturesEnabled) { - mSource = AINPUT_SOURCE_MOUSE; - mDeviceMode = DEVICE_MODE_POINTER; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && mParameters.hasAssociatedDisplay) { - mSource = AINPUT_SOURCE_TOUCHSCREEN; - mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { - mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; - mDeviceMode = DEVICE_MODE_NAVIGATION; - } else { - mSource = AINPUT_SOURCE_TOUCHPAD; - mDeviceMode = DEVICE_MODE_UNSCALED; - } - - // Ensure we have valid X and Y axes. - if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { - ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " - "The device will be inoperable.", getDeviceName().string()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - - // Get associated display dimensions. - bool viewportChanged = false; - DisplayViewport newViewport; - if (mParameters.hasAssociatedDisplay) { - if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) { - ALOGI(INDENT "Touch device '%s' could not query the properties of its associated " - "display. The device will be inoperable until the display size " - "becomes available.", - getDeviceName().string()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - } else { - newViewport.setNonDisplayViewport(rawWidth, rawHeight); - } - if (mViewport != newViewport) { - mViewport = newViewport; - viewportChanged = true; - - if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { - // Convert rotated viewport to natural surface coordinates. - int32_t naturalLogicalWidth, naturalLogicalHeight; - int32_t naturalPhysicalWidth, naturalPhysicalHeight; - int32_t naturalPhysicalLeft, naturalPhysicalTop; - int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { - case DISPLAY_ORIENTATION_90: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; - naturalPhysicalTop = mViewport.physicalLeft; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_180: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; - naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - case DISPLAY_ORIENTATION_270: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.physicalTop; - naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_0: - default: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.physicalLeft; - naturalPhysicalTop = mViewport.physicalTop; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - } - - mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; - mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; - mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; - mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; - - mSurfaceOrientation = mParameters.orientationAware ? - mViewport.orientation : DISPLAY_ORIENTATION_0; - } else { - mSurfaceWidth = rawWidth; - mSurfaceHeight = rawHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceOrientation = DISPLAY_ORIENTATION_0; - } - } - - // If moving between pointer modes, need to reset some state. - bool deviceModeChanged = mDeviceMode != oldDeviceMode; - if (deviceModeChanged) { - mOrientedRanges.clear(); - } - - // Create pointer controller if needed. - if (mDeviceMode == DEVICE_MODE_POINTER || - (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { - if (mPointerController == NULL) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - } - } else { - mPointerController.clear(); - } - - if (viewportChanged || deviceModeChanged) { - ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " - "display id %d", - getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight, - mSurfaceOrientation, mDeviceMode, mViewport.displayId); - - // Configure X and Y factors. - mXScale = float(mSurfaceWidth) / rawWidth; - mYScale = float(mSurfaceHeight) / rawHeight; - mXTranslate = -mSurfaceLeft; - mYTranslate = -mSurfaceTop; - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; - - mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mSource; - mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mSource; - - configureVirtualKeys(); - - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mGeometricScale = avg(mXScale, mYScale); - - // Size of diagonal axis. - float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Size factors. - if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { - if (mRawPointerAxes.touchMajor.valid - && mRawPointerAxes.touchMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; - } else if (mRawPointerAxes.toolMajor.valid - && mRawPointerAxes.toolMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; - } else { - mSizeScale = 0.0f; - } - - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; - - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; - - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; - - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; - - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; - } else { - mSizeScale = 0.0f; - } - - // Pressure factors. - mPressureScale = 0; - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL - || mCalibration.pressureCalibration - == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - } else if (mRawPointerAxes.pressure.valid - && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } - } - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = 1.0; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; - - // Tilt - mTiltXCenter = 0; - mTiltXScale = 0; - mTiltYCenter = 0; - mTiltYScale = 0; - mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; - if (mHaveTilt) { - mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, - mRawPointerAxes.tiltX.maxValue); - mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, - mRawPointerAxes.tiltY.maxValue); - mTiltXScale = M_PI / 180; - mTiltYScale = M_PI / 180; - - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; - } - - // Orientation - mOrientationScale = 0; - if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } else if (mCalibration.orientationCalibration != - Calibration::ORIENTATION_CALIBRATION_NONE) { - if (mCalibration.orientationCalibration - == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawPointerAxes.orientation.valid) { - if (mRawPointerAxes.orientation.maxValue > 0) { - mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; - } else if (mRawPointerAxes.orientation.minValue < 0) { - mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; - } else { - mOrientationScale = 0; - } - } - } - - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } - - // Distance - mDistanceScale = 0; - if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { - if (mCalibration.distanceCalibration - == Calibration::DISTANCE_CALIBRATION_SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } - } - - mOrientedRanges.haveDistance = true; - - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = - mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = - mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = - mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; - } - - // Compute oriented precision, scales and ranges. - // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of surface. - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - - mOrientedRanges.x.min = mYTranslate; - mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - - mOrientedRanges.y.min = mXTranslate; - mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; - break; - - default: - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - - mOrientedRanges.x.min = mXTranslate; - mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - - mOrientedRanges.y.min = mYTranslate; - mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; - break; - } - - if (mDeviceMode == DEVICE_MODE_POINTER) { - // Compute pointer gesture detection parameters. - float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Scale movements such that one whole swipe of the touch pad covers a - // given area relative to the diagonal size of the display when no acceleration - // is applied. - // Assume that the touch pad has a square aspect ratio such that movements in - // X and Y of the same number of raw units cover the same physical distance. - mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYMovementScale = mPointerXMovementScale; - - // Scale zooms to cover a smaller range of the display than movements do. - // This value determines the area around the pointer that is affected by freeform - // pointer gestures. - mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYZoomScale = mPointerXZoomScale; - - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = - mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; - - // Abort current pointer usages because the state has changed. - abortPointerUsage(when, 0 /*policyFlags*/); - } - - // Inform the dispatcher about the changes. - *outResetNeeded = true; - bumpGeneration(); - } -} - -void TouchInputMapper::dumpSurface(String8& dump) { - dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, " - "logicalFrame=[%d, %d, %d, %d], " - "physicalFrame=[%d, %d, %d, %d], " - "deviceSize=[%d, %d]\n", - mViewport.displayId, mViewport.orientation, - mViewport.logicalLeft, mViewport.logicalTop, - mViewport.logicalRight, mViewport.logicalBottom, - mViewport.physicalLeft, mViewport.physicalTop, - mViewport.physicalRight, mViewport.physicalBottom, - mViewport.deviceWidth, mViewport.deviceHeight); - - dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); - dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); - dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); -} - -void TouchInputMapper::configureVirtualKeys() { - Vector<VirtualKeyDefinition> virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); - - mVirtualKeys.clear(); - - if (virtualKeyDefinitions.size() == 0) { - return; - } - - mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); - - int32_t touchScreenLeft = mRawPointerAxes.x.minValue; - int32_t touchScreenTop = mRawPointerAxes.y.minValue; - int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - - for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const VirtualKeyDefinition& virtualKeyDefinition = - virtualKeyDefinitions[i]; - - mVirtualKeys.add(); - VirtualKey& virtualKey = mVirtualKeys.editTop(); - - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) { - ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", - virtualKey.scanCode); - mVirtualKeys.pop(); // drop the key - continue; - } - - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; - - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; - - virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - } -} - -void TouchInputMapper::dumpVirtualKeys(String8& dump) { - if (!mVirtualKeys.isEmpty()) { - dump.append(INDENT3 "Virtual Keys:\n"); - - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); - dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, " - "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", - i, virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, - virtualKey.hitTop, virtualKey.hitBottom); - } - } -} - -void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); - Calibration& out = mCalibration; - - // Size - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { - if (sizeCalibrationString == "none") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } else if (sizeCalibrationString == "geometric") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } else if (sizeCalibrationString == "diameter") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; - } else if (sizeCalibrationString == "box") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; - } else if (sizeCalibrationString == "area") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; - } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", - sizeCalibrationString.string()); - } - } - - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), - out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), - out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), - out.sizeIsSummed); - - // Pressure - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { - if (pressureCalibrationString == "none") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } else if (pressureCalibrationString == "physical") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } else if (pressureCalibrationString == "amplitude") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else if (pressureCalibrationString != "default") { - ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); - } - } - - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), - out.pressureScale); - - // Orientation - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { - if (orientationCalibrationString == "none") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } else if (orientationCalibrationString == "interpolated") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else if (orientationCalibrationString == "vector") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; - } else if (orientationCalibrationString != "default") { - ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); - } - } - - // Distance - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { - if (distanceCalibrationString == "none") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } else if (distanceCalibrationString == "scaled") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } else if (distanceCalibrationString != "default") { - ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); - } - } - - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), - out.distanceScale); - - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { - if (coverageCalibrationString == "none") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } else if (coverageCalibrationString == "box") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; - } else if (coverageCalibrationString != "default") { - ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); - } - } -} - -void TouchInputMapper::resolveCalibration() { - // Size - if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } - } else { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } - - // Pressure - if (mRawPointerAxes.pressure.valid) { - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } - } else { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } - - // Orientation - if (mRawPointerAxes.orientation.valid) { - if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } - } else { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } - - // Distance - if (mRawPointerAxes.distance.valid) { - if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } - } else { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } - - // Coverage - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { - mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } -} - -void TouchInputMapper::dumpCalibration(String8& dump) { - dump.append(INDENT3 "Calibration:\n"); - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.size.calibration: none\n"); - break; - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - dump.append(INDENT4 "touch.size.calibration: geometric\n"); - break; - case Calibration::SIZE_CALIBRATION_DIAMETER: - dump.append(INDENT4 "touch.size.calibration: diameter\n"); - break; - case Calibration::SIZE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.size.calibration: box\n"); - break; - case Calibration::SIZE_CALIBRATION_AREA: - dump.append(INDENT4 "touch.size.calibration: area\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveSizeScale) { - dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n", - mCalibration.sizeScale); - } - - if (mCalibration.haveSizeBias) { - dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n", - mCalibration.sizeBias); - } - - if (mCalibration.haveSizeIsSummed) { - dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); - } - - // Pressure - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.pressure.calibration: none\n"); - break; - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump.append(INDENT4 "touch.pressure.calibration: physical\n"); - break; - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.havePressureScale) { - dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", - mCalibration.pressureScale); - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_NONE: - dump.append(INDENT4 "touch.orientation.calibration: none\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: - dump.append(INDENT4 "touch.orientation.calibration: vector\n"); - break; - default: - ALOG_ASSERT(false); - } - - // Distance - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.distance.calibration: none\n"); - break; - case Calibration::DISTANCE_CALIBRATION_SCALED: - dump.append(INDENT4 "touch.distance.calibration: scaled\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveDistanceScale) { - dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", - mCalibration.distanceScale); - } - - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.coverage.calibration: none\n"); - break; - case Calibration::COVERAGE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.coverage.calibration: box\n"); - break; - default: - ALOG_ASSERT(false); - } -} - -void TouchInputMapper::reset(nsecs_t when) { - mCursorButtonAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - mTouchButtonAccumulator.reset(getDevice()); - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); - mPointerUsage = POINTER_USAGE_NONE; - mSentHoverEnter = false; - mDownTime = 0; - - mCurrentVirtualKey.down = false; - - mPointerGesture.reset(); - mPointerSimple.reset(); - - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } - - InputMapper::reset(when); -} - -void TouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void TouchInputMapper::sync(nsecs_t when) { - // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() - | mCursorButtonAccumulator.getButtonState(); - - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); - mCursorScrollAccumulator.finishSync(); - - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); - -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); - } -#endif - - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); - - if (mDeviceMode == DEVICE_MODE_DISABLED) { - // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } - - // Initial downs on external touch devices should wake the device. - // We don't do this for internal touch screens to prevent them from waking - // up in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - if (getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - } - - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); - - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); - } - - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); - - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } - } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } - } - - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } - - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } - - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); - } - - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); - } - - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; - - // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; -} - -void TouchInputMapper::timeoutExpired(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - if (mPointerUsage == POINTER_USAGE_GESTURES) { - dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); - } - } -} - -bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { - // Check for release of a virtual key. - if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { - // Pointer went up while virtual key was down. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - return true; - } - - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { - // Pointer is still within the space of the virtual key. - return true; - } - } - - // Pointer left virtual key area or another pointer also went down. - // Send key cancellation but do not consume the touch yet. - // This is useful when the user swipes through from the virtual key area - // into the main display surface. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED); - } - } - - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { - // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (!isPointInsideSurface(pointer.x, pointer.y)) { - // If exactly one pointer went down, check for virtual key hit. - // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey) { - mCurrentVirtualKey.down = true; - mCurrentVirtualKey.downTime = when; - mCurrentVirtualKey.keyCode = virtualKey->keyCode; - mCurrentVirtualKey.scanCode = virtualKey->scanCode; - mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( - when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); - - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, - mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_DOWN, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - } - } - return true; - } - } - - // Disable all virtual key touches that happen within a short time interval of the - // most recent touch within the screen area. The idea is to filter out stray - // virtual key presses when interacting with the touch screen. - // - // Problems we're trying to solve: - // - // 1. While scrolling a list or dragging the window shade, the user swipes down into a - // virtual key area that is implemented by a separate touch panel and accidentally - // triggers a virtual key. - // - // 2. While typing in the on screen keyboard, the user taps slightly outside the screen - // area and accidentally triggers a virtual key. This often happens when virtual keys - // are layed out below the screen near to where the on screen keyboard's space bar - // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { - mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); - } - return false; -} - -void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags) { - int32_t keyCode = mCurrentVirtualKey.keyCode; - int32_t scanCode = mCurrentVirtualKey.scanCode; - nsecs_t downTime = mCurrentVirtualKey.downTime; - int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - - NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - getListener()->notifyKey(&args); -} - -void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - - if (currentIdBits == lastIdBits) { - if (!currentIdBits.isEmpty()) { - // No pointer id changes so this is a move event. - // The listener takes care of batching moves so we don't have to deal with that here. - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } else { - // There may be pointers going up and pointers going down and pointers moving - // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); - BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - BitSet32 dispatchedIdBits(lastIdBits.value); - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - moveIdBits); - if (buttonState != mLastButtonState) { - moveNeeded = true; - } - - // Dispatch pointer up events. - while (!upIdBits.isEmpty()) { - uint32_t upId = upIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - dispatchedIdBits.clearBit(upId); - } - - // Dispatch move events if any of the remaining pointers moved from their old locations. - // Although applications receive new locations as part of individual pointer up - // events, they do not generally handle them except when presented in a move event. - if (moveNeeded) { - ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - - // Dispatch pointer down events using the new pointer locations. - while (!downIdBits.isEmpty()) { - uint32_t downId = downIdBits.clearFirstMarkedBit(); - dispatchedIdBits.markBit(downId); - - if (dispatchedIdBits.count() == 1) { - // First pointer is going down. Set down time. - mDownTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, downId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } -} - -void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { - if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { - int32_t metaState = getContext()->getGlobalMetaState(); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = false; - } -} - -void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = true; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; - - // Walk through the the active pointers and map device coordinates onto - // surface coordinates and adjust for display orientation. - for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; - - // Size - float touchMajor, touchMinor, toolMajor, toolMinor, size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - case Calibration::SIZE_CALIBRATION_DIAMETER: - case Calibration::SIZE_CALIBRATION_BOX: - case Calibration::SIZE_CALIBRATION_AREA: - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { - touchMajor = in.touchMajor; - touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; - toolMajor = in.toolMajor; - toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.touchMajor.valid) { - toolMajor = touchMajor = in.touchMajor; - toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid - ? in.touchMinor : in.touchMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.toolMajor.valid) { - touchMajor = toolMajor = in.toolMajor; - touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid - ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.toolMinor.valid - ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; - } else { - ALOG_ASSERT(false, "No touch or tool axes. " - "Size calibration should have been resolved to NONE."); - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - } - - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); - if (touchingCount > 1) { - touchMajor /= touchingCount; - touchMinor /= touchingCount; - toolMajor /= touchingCount; - toolMinor /= touchingCount; - size /= touchingCount; - } - } - - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { - touchMajor *= mGeometricScale; - touchMinor *= mGeometricScale; - toolMajor *= mGeometricScale; - toolMinor *= mGeometricScale; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { - touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; - touchMinor = touchMajor; - toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; - toolMinor = toolMajor; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { - touchMinor = touchMajor; - toolMinor = toolMajor; - } - - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); - size *= mSizeScale; - break; - default: - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - break; - } - - // Pressure - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = in.pressure * mPressureScale; - break; - default: - pressure = in.isHovering ? 0 : 1; - break; - } - - // Tilt and Orientation - float tilt; - float orientation; - if (mHaveTilt) { - float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; - float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; - orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); - tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); - } else { - tilt = 0; - - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mOrientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float confidence = hypotf(c1, c2); - float scale = 1.0f + confidence / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; - } else { - orientation = 0; - } - break; - } - default: - orientation = 0; - } - } - - // Distance - float distance; - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_SCALED: - distance = in.distance * mDistanceScale; - break; - default: - distance = 0; - } - - // Coverage - int32_t rawLeft, rawTop, rawRight, rawBottom; - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_BOX: - rawLeft = (in.toolMinor & 0xffff0000) >> 16; - rawRight = in.toolMinor & 0x0000ffff; - rawBottom = in.toolMajor & 0x0000ffff; - rawTop = (in.toolMajor & 0xffff0000) >> 16; - break; - default: - rawLeft = rawTop = rawRight = rawBottom = 0; - break; - } - - // X, Y, and the bounding box for coverage information - // Adjust coords for surface orientation. - float x, y, left, top, right, bottom; - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; - left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - orientation -= M_PI_2; - if (orientation < - M_PI_2) { - orientation += M_PI; - } - break; - case DISPLAY_ORIENTATION_180: - x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; - y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; - left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - break; - case DISPLAY_ORIENTATION_270: - x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; - y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - orientation += M_PI_2; - if (orientation > M_PI_2) { - orientation -= M_PI; - } - break; - default: - x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - break; - } - - // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; - out.clear(); - out.setAxisValue(AMOTION_EVENT_AXIS_X, x); - out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); - out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); - out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); - } else { - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); - } - - // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; - uint32_t id = in.id; - properties.clear(); - properties.id = id; - properties.toolType = in.toolType; - - // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; - } -} - -void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, - PointerUsage pointerUsage) { - if (pointerUsage != mPointerUsage) { - abortPointerUsage(when, policyFlags); - mPointerUsage = pointerUsage; - } - - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); - break; - case POINTER_USAGE_STYLUS: - dispatchPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - dispatchPointerMouse(when, policyFlags); - break; - default: - break; - } -} - -void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - abortPointerGestures(when, policyFlags); - break; - case POINTER_USAGE_STYLUS: - abortPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - abortPointerMouse(when, policyFlags); - break; - default: - break; - } - - mPointerUsage = POINTER_USAGE_NONE; -} - -void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, - bool isTimeout) { - // Update current gesture coordinates. - bool cancelPreviousGesture, finishPreviousGesture; - bool sendEvents = preparePointerGestures(when, - &cancelPreviousGesture, &finishPreviousGesture, isTimeout); - if (!sendEvents) { - return; - } - if (finishPreviousGesture) { - cancelPreviousGesture = false; - } - - // Update the pointer presentation and spots. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - if (finishPreviousGesture || cancelPreviousGesture) { - mPointerController->clearSpots(); - } - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits); - } else { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - } - - // Show or hide the pointer if needed. - switch (mPointerGesture.currentGestureMode) { - case PointerGesture::NEUTRAL: - case PointerGesture::QUIET: - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS - && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) { - // Remind the user of where the pointer is after finishing a gesture with spots. - mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); - } - break; - case PointerGesture::TAP: - case PointerGesture::TAP_DRAG: - case PointerGesture::BUTTON_CLICK_OR_DRAG: - case PointerGesture::HOVER: - case PointerGesture::PRESS: - // Unfade the pointer when the current gesture manipulates the - // area directly under the pointer. - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - break; - case PointerGesture::SWIPE: - case PointerGesture::FREEFORM: - // Fade the pointer when the current gesture manipulates a different - // area and there are spots to guide the user experience. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } else { - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - break; - } - - // Send events! - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP - || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE - || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; - bool moveNeeded = false; - if (down && !cancelPreviousGesture && !finishPreviousGesture - && !mPointerGesture.lastGestureIdBits.isEmpty() - && !mPointerGesture.currentGestureIdBits.isEmpty()) { - BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value - & mPointerGesture.lastGestureIdBits.value); - moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - movedGestureIdBits); - if (buttonState != mLastButtonState) { - moveNeeded = true; - } - } - - // Send motion events for all pointers that went up or were canceled. - BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); - if (!dispatchedGestureIdBits.isEmpty()) { - if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clear(); - } else { - BitSet32 upGestureIdBits; - if (finishPreviousGesture) { - upGestureIdBits = dispatchedGestureIdBits; - } else { - upGestureIdBits.value = dispatchedGestureIdBits.value - & ~mPointerGesture.currentGestureIdBits.value; - } - while (!upGestureIdBits.isEmpty()) { - uint32_t id = upGestureIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clearBit(id); - } - } - } - - // Send motion events for all pointers that moved. - if (moveNeeded) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Send motion events for all pointers that went down. - if (down) { - BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value - & ~dispatchedGestureIdBits.value); - while (!downGestureIdBits.isEmpty()) { - uint32_t id = downGestureIdBits.clearFirstMarkedBit(); - dispatchedGestureIdBits.markBit(id); - - if (dispatchedGestureIdBits.count() == 1) { - mPointerGesture.downTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - } - } - - // Send motion events for hover. - if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } else if (dispatchedGestureIdBits.isEmpty() - && !mPointerGesture.lastGestureIdBits.isEmpty()) { - // Synthesize a hover move event after all pointers go up to indicate that - // the pointer is hovering again even if the user is not currently touching - // the touch pad. This ensures that a view will receive a fresh hover enter - // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - - PointerCoords pointerCoords; - pointerCoords.clear(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mViewport.displayId, 1, &pointerProperties, &pointerCoords, - 0, 0, mPointerGesture.downTime); - getListener()->notifyMotion(&args); - } - - // Update state. - mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; - if (!down) { - mPointerGesture.lastGestureIdBits.clear(); - } else { - mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; - for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - mPointerGesture.lastGestureProperties[index].copyFrom( - mPointerGesture.currentGestureProperties[index]); - mPointerGesture.lastGestureCoords[index].copyFrom( - mPointerGesture.currentGestureCoords[index]); - mPointerGesture.lastGestureIdToIndex[id] = index; - } - } -} - -void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { - // Cancel previously dispatches pointers. - if (!mPointerGesture.lastGestureIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Reset the current pointer gesture. - mPointerGesture.reset(); - mPointerVelocityControl.reset(); - - // Remove any current spots. - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } -} - -bool TouchInputMapper::preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { - *outCancelPreviousGesture = false; - *outFinishPreviousGesture = false; - - // Handle TAP timeout. - if (isTimeout) { -#if DEBUG_GESTURES - ALOGD("Gestures: Processing timeout"); -#endif - - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime - + mConfig.pointerGestureTapDragInterval); - } else { - // The tap is finished. -#if DEBUG_GESTURES - ALOGD("Gestures: TAP finished"); -#endif - *outFinishPreviousGesture = true; - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - return true; - } - } - - // We did not handle this timeout. - return false; - } - - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); - - // Update the velocity tracker. - { - VelocityTracker::Position positions[MAX_POINTERS]; - uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - positions[count].x = pointer.x * mPointerXMovementScale; - positions[count].y = pointer.y * mPointerYMovementScale; - } - mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); - } - - // Pick a new active touch id if needed. - // Choose an arbitrary pointer that just went down, if there is one. - // Otherwise choose an arbitrary remaining pointer. - // This guarantees we always have an active touch id when there is at least one pointer. - // We keep the same active touch id for as long as possible. - int32_t lastActiveTouchId = mPointerGesture.activeTouchId; - int32_t activeTouchId = lastActiveTouchId; - if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); - mPointerGesture.firstTouchTime = when; - } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { - if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); - } else { - activeTouchId = mPointerGesture.activeTouchId = -1; - } - } - - // Determine whether we are in quiet time. - bool isQuietTime = false; - if (activeTouchId < 0) { - mPointerGesture.resetQuietTime(); - } else { - isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; - if (!isQuietTime) { - if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS - || mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) - && currentFingerCount < 2) { - // Enter quiet time when exiting swipe or freeform state. - // This is to prevent accidentally entering the hover state and flinging the - // pointer when finishing a swipe and there is still one pointer left onscreen. - isQuietTime = true; - } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { - // Enter quiet time when releasing the button and there are still two or more - // fingers down. This may indicate that one finger was used to press the button - // but it has not gone up yet. - isQuietTime = true; - } - if (isQuietTime) { - mPointerGesture.quietTime = when; - } - } - } - - // Switch states based on button and pointer state. - if (isQuietTime) { - // Case 1: Quiet time. (QUIET) -#if DEBUG_GESTURES - ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime - + mConfig.pointerGestureQuietInterval - when) * 0.000001f); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { - *outFinishPreviousGesture = true; - } - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::QUIET; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { - // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) - // The pointer follows the active touch point. - // Emit DOWN, MOVE, UP events at the pointer location. - // - // Only the active touch matters; other fingers are ignored. This policy helps - // to handle the case where the user places a second finger on the touch pad - // to apply the necessary force to depress an integrated button below the surface. - // We don't want the second finger to be delivered to applications. - // - // For this to work well, we need to make sure to track the pointer that is really - // active. If the user first puts one finger down to click then adds another - // finger to drag then the active pointer should switch to the finger that is - // being dragged. -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentFingerCount=%d", activeTouchId, currentFingerCount); -#endif - // Reset state when just starting. - if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { - *outFinishPreviousGesture = true; - mPointerGesture.activeGestureId = 0; - } - - // Switch pointers if needed. - // Find the fastest pointer and follow it. - if (activeTouchId >= 0 && currentFingerCount > 1) { - int32_t bestId = -1; - float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); - if (speed > bestSpeed) { - bestId = id; - bestSpeed = speed; - } - } - } - if (bestId >= 0 && bestId != activeTouchId) { - mPointerGesture.activeTouchId = activeTouchId = bestId; -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); -#endif - } - } - - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the click will occur at the position of the anchor - // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (currentFingerCount == 0) { - // Case 3. No fingers down and button is not pressed. (NEUTRAL) - if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { - *outFinishPreviousGesture = true; - } - - // Watch for taps coming out of HOVER or TAP_DRAG mode. - // Checking for taps after TAP_DRAG allows us to detect double-taps. - bool tapped = false; - if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER - || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) - && lastFingerCount == 1) { - if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP"); -#endif - - mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when - + mConfig.pointerGestureTapDragInterval); - - mPointerGesture.activeGestureId = 0; - mPointerGesture.currentGestureMode = PointerGesture::TAP; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit( - mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[ - mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = - mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - tapped = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, %0.3fms since down", - (when - mPointerGesture.tapDownTime) * 0.000001f); -#endif - } - } - - mPointerVelocityControl.reset(); - - if (!tapped) { -#if DEBUG_GESTURES - ALOGD("Gestures: NEUTRAL"); -#endif - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - } - } else if (currentFingerCount == 1) { - // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) - // The pointer follows the active touch point. - // When in HOVER, emit HOVER_MOVE events at the pointer location. - // When in TAP_DRAG, emit MOVE events at the pointer location. - ALOG_ASSERT(activeTouchId >= 0); - - mPointerGesture.currentGestureMode = PointerGesture::HOVER; - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", - (when - mPointerGesture.tapUpTime) * 0.000001f); -#endif - } - } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } - - if (mLastFingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) - * mPointerXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - bool down; - if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP_DRAG"); -#endif - down = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: HOVER"); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { - *outFinishPreviousGesture = true; - } - mPointerGesture.activeGestureId = 0; - down = false; - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - down ? 1.0f : 0.0f); - - if (lastFingerCount == 0 && currentFingerCount != 0) { - mPointerGesture.resetTap(); - mPointerGesture.tapDownTime = when; - mPointerGesture.tapX = x; - mPointerGesture.tapY = y; - } - } else { - // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) - // We need to provide feedback for each finger that goes down so we cannot wait - // for the fingers to move before deciding what to do. - // - // The ambiguous case is deciding what to do when there are two fingers down but they - // have not moved enough to determine whether they are part of a drag or part of a - // freeform gesture, or just a press or long-press at the pointer location. - // - // When there are two fingers we start with the PRESS hypothesis and we generate a - // down at the pointer location. - // - // When the two fingers move enough or when additional fingers are added, we make - // a decision to transition into SWIPE or FREEFORM mode accordingly. - ALOG_ASSERT(activeTouchId >= 0); - - bool settled = when >= mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval; - if (mPointerGesture.lastGestureMode != PointerGesture::PRESS - && mPointerGesture.lastGestureMode != PointerGesture::SWIPE - && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - *outFinishPreviousGesture = true; - } else if (!settled && currentFingerCount > lastFingerCount) { - // Additional pointers have gone down but not yet settled. - // Reset the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - *outCancelPreviousGesture = true; - } else { - // Continue previous gesture. - mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; - } - - if (*outFinishPreviousGesture || *outCancelPreviousGesture) { - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; - mPointerGesture.referenceIdBits.clear(); - mPointerVelocityControl.reset(); - - // Use the centroid and pointer location as the reference points for the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( - &mPointerGesture.referenceTouchX, - &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); - } - - // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value - & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - mPointerGesture.referenceDeltas[id].dx = 0; - mPointerGesture.referenceDeltas[id].dy = 0; - } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; - - // Add delta for all fingers and calculate a common movement delta. - float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { - bool first = (idBits == commonIdBits); - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx += cpd.x - lpd.x; - delta.dy += cpd.y - lpd.y; - - if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; - } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); - } - } - - // Consider transitions from PRESS to SWIPE or MULTITOUCH. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { - float dist[MAX_POINTER_ID + 1]; - int32_t distOverThreshold = 0; - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - dist[id] = hypotf(delta.dx * mPointerXZoomScale, - delta.dy * mPointerYZoomScale); - if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { - distOverThreshold += 1; - } - } - - // Only transition when at least two pointers have moved further than - // the minimum distance threshold. - if (distOverThreshold >= 2) { - if (currentFingerCount > 2) { - // There are more than two pointers, switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); - uint32_t id1 = idBits.clearFirstMarkedBit(); - uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); - float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); - if (mutualDistance > mPointerGestureMaxSwipeWidth) { - // There are two pointers but they are too far apart for a SWIPE, - // switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", - mutualDistance, mPointerGestureMaxSwipeWidth); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are two pointers. Wait for both pointers to start moving - // before deciding whether this is a SWIPE or FREEFORM gesture. - float dist1 = dist[id1]; - float dist2 = dist[id2]; - if (dist1 >= mConfig.pointerGestureMultitouchMinDistance - && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { - // Calculate the dot product of the displacement vectors. - // When the vectors are oriented in approximately the same direction, - // the angle betweeen them is near zero and the cosine of the angle - // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). - PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; - PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dx1 = delta1.dx * mPointerXZoomScale; - float dy1 = delta1.dy * mPointerYZoomScale; - float dx2 = delta2.dx * mPointerXZoomScale; - float dy2 = delta2.dy * mPointerYZoomScale; - float dot = dx1 * dx2 + dy1 * dy2; - float cosine = dot / (dist1 * dist2); // denominator always > 0 - if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { - // Pointers are moving in the same direction. Switch to SWIPE. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to SWIPE, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - mPointerGesture.currentGestureMode = PointerGesture::SWIPE; - } else { - // Pointers are moving in different directions. Switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - } - } - } - } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // Switch from SWIPE to FREEFORM if additional pointers go down. - // Cancel previous gesture. - if (currentFingerCount > 2) { -#if DEBUG_GESTURES - ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - - // Move the reference points based on the overall group motion of the fingers - // except in PRESS mode while waiting for a transition to occur. - if (mPointerGesture.currentGestureMode != PointerGesture::PRESS - && (commonDeltaX || commonDeltaY)) { - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx = 0; - delta.dy = 0; - } - - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; - - commonDeltaX *= mPointerXMovementScale; - commonDeltaY *= mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); - mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); - - mPointerGesture.referenceGestureX += commonDeltaX; - mPointerGesture.referenceGestureY += commonDeltaY; - } - - // Report gestures. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // PRESS or SWIPE mode. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.referenceGestureX); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.referenceGestureY); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - // FREEFORM mode. -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - - BitSet32 mappedTouchIdBits; - BitSet32 usedGestureIdBits; - if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - // Initially, assign the active gesture id to the active touch point - // if there is one. No other touch id bits are mapped yet. - if (!*outCancelPreviousGesture) { - mappedTouchIdBits.markBit(activeTouchId); - usedGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = - mPointerGesture.activeGestureId; - } else { - mPointerGesture.activeGestureId = -1; - } - } else { - // Otherwise, assume we mapped all touches from the previous frame. - // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; - usedGestureIdBits = mPointerGesture.lastGestureIdBits; - - // Check whether we need to choose a new active gesture id because the - // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); - !upTouchIdBits.isEmpty(); ) { - uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); - uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; - if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { - mPointerGesture.activeGestureId = -1; - break; - } - } - } - -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM follow up " - "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " - "activeGestureId=%d", - mappedTouchIdBits.value, usedGestureIdBits.value, - mPointerGesture.activeGestureId); -#endif - - BitSet32 idBits(mCurrentFingerIdBits); - for (uint32_t i = 0; i < currentFingerCount; i++) { - uint32_t touchId = idBits.clearFirstMarkedBit(); - uint32_t gestureId; - if (!mappedTouchIdBits.hasBit(touchId)) { - gestureId = usedGestureIdBits.markFirstUnmarkedBit(); - mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "new mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } else { - gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "existing mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } - mPointerGesture.currentGestureIdBits.markBit(gestureId); - mPointerGesture.currentGestureIdToIndex[gestureId] = i; - - const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); - float deltaX = (pointer.x - mPointerGesture.referenceTouchX) - * mPointerXZoomScale; - float deltaY = (pointer.y - mPointerGesture.referenceTouchY) - * mPointerYZoomScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - - mPointerGesture.currentGestureProperties[i].clear(); - mPointerGesture.currentGestureProperties[i].id = gestureId; - mPointerGesture.currentGestureProperties[i].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[i].clear(); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } - - if (mPointerGesture.activeGestureId < 0) { - mPointerGesture.activeGestureId = - mPointerGesture.currentGestureIdBits.firstMarkedBit(); -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM new " - "activeGestureId=%d", mPointerGesture.activeGestureId); -#endif - } - } - } - - mPointerController->setButtonState(mCurrentButtonState); - -#if DEBUG_GESTURES - ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " - "currentGestureMode=%d, currentGestureIdBits=0x%08x, " - "lastGestureMode=%d, lastGestureIdBits=0x%08x", - toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), - mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, - mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); - for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } - for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - return true; -} - -void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); - mPointerController->setPosition(x, y); - - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); - down = !hovering; - - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; - } else { - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); -} - -void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) - * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - down = isPointerDown(mCurrentButtonState); - hovering = !down; - - float x, y; - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - hovering ? 0.0f : 1.0f); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; - } else { - mPointerVelocityControl.reset(); - - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); - - mPointerVelocityControl.reset(); -} - -void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering) { - int32_t metaState = getContext()->getGlobalMetaState(); - - if (mPointerController != NULL) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - } - - if (mPointerSimple.down && !down) { - mPointerSimple.down = false; - - // Send up. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (mPointerSimple.hovering && !hovering) { - mPointerSimple.hovering = false; - - // Send hover exit. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (down) { - if (!mPointerSimple.down) { - mPointerSimple.down = true; - mPointerSimple.downTime = when; - - // Send down. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Send move. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (hovering) { - if (!mPointerSimple.hovering) { - mPointerSimple.hovering = true; - - // Send hover enter. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Send hover move. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; - mWheelYVelocityControl.move(when, NULL, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, NULL); - - // Send scroll. - PointerCoords pointerCoords; - pointerCoords.copyFrom(mPointerSimple.currentCoords); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Save state. - if (down || hovering) { - mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); - mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); - } else { - mPointerSimple.reset(); - } -} - -void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - dispatchPointerSimple(when, policyFlags, false, false); -} - -void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { - PointerCoords pointerCoords[MAX_POINTERS]; - PointerProperties pointerProperties[MAX_POINTERS]; - uint32_t pointerCount = 0; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = idToIndex[id]; - pointerProperties[pointerCount].copyFrom(properties[index]); - pointerCoords[pointerCount].copyFrom(coords[index]); - - if (changedId >= 0 && id == uint32_t(changedId)) { - action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - pointerCount += 1; - } - - ALOG_ASSERT(pointerCount != 0); - - if (changedId >= 0 && pointerCount == 1) { - // Replace initial down and final up action. - // We can compare the action without masking off the changed pointer index - // because we know the index is 0. - if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { - action = AMOTION_EVENT_ACTION_DOWN; - } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { - action = AMOTION_EVENT_ACTION_UP; - } else { - // Can't happen. - ALOG_ASSERT(false); - } - } - - NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, - action, flags, metaState, buttonState, edgeFlags, - mViewport.displayId, pointerCount, pointerProperties, pointerCoords, - xPrecision, yPrecision, downTime); - getListener()->notifyMotion(&args); -} - -bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, - BitSet32 idBits) const { - bool changed = false; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t inIndex = inIdToIndex[id]; - uint32_t outIndex = outIdToIndex[id]; - - const PointerProperties& curInProperties = inProperties[inIndex]; - const PointerCoords& curInCoords = inCoords[inIndex]; - PointerProperties& curOutProperties = outProperties[outIndex]; - PointerCoords& curOutCoords = outCoords[outIndex]; - - if (curInProperties != curOutProperties) { - curOutProperties.copyFrom(curInProperties); - changed = true; - } - - if (curInCoords != curOutCoords) { - curOutCoords.copyFrom(curInCoords); - changed = true; - } - } - return changed; -} - -void TouchInputMapper::fadePointer() { - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue - && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; -} - -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( - int32_t x, int32_t y) { - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, - virtualKey.keyCode, virtualKey.scanCode, - virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return & virtualKey; - } - } - - return NULL; -} - -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; - - mCurrentRawPointerData.clearIdBits(); - - if (currentPointerCount == 0) { - // No pointers to assign. - return; - } - - if (lastPointerCount == 0) { - // All pointers are new. - for (uint32_t i = 0; i < currentPointerCount; i++) { - uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); - } - return; - } - - if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); - return; - } - - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - // The pointers must have the same tool type but it is possible for them to - // transition from hovering to touching or vice-versa while retaining the same id. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; - if (currentPointer.toolType == lastPointer.toolType) { - int64_t deltaX = currentPointer.x - lastPointer.x; - int64_t deltaY = currentPointer.y - lastPointer.y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { - while (heapSize > 0) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - } - - heapSize -= 1; - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to pointers that were not matched in the process. - for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { - uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); - uint32_t id = usedIdBits.markFirstUnmarkedBit(); - - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - assigned: cur=%d, id=%d", - currentPointerIndex, id); -#endif - } -} - -int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - if (virtualKey.keyCode == keyCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - if (virtualKey.scanCode == scanCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - - for (size_t i = 0; i < numCodes; i++) { - if (virtualKey.keyCode == keyCodes[i]) { - outFlags[i] = 1; - } - } - } - - return true; -} - - -// --- SingleTouchInputMapper --- - -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -SingleTouchInputMapper::~SingleTouchInputMapper() { -} - -void SingleTouchInputMapper::reset(nsecs_t when) { - mSingleTouchMotionAccumulator.reset(getDevice()); - - TouchInputMapper::reset(when); -} - -void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mSingleTouchMotionAccumulator.process(rawEvent); -} - -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { - if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid - && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); - - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; - outPointer.id = 0; - outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); - outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); - outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - outPointer.touchMajor = 0; - outPointer.touchMinor = 0; - outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.orientation = 0; - outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); - outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); - outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - outPointer.isHovering = isHovering; - } -} - -void SingleTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); - getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); -} - -bool SingleTouchInputMapper::hasStylus() const { - return mTouchButtonAccumulator.hasStylus(); -} - - -// --- MultiTouchInputMapper --- - -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -MultiTouchInputMapper::~MultiTouchInputMapper() { -} - -void MultiTouchInputMapper::reset(nsecs_t when) { - mMultiTouchMotionAccumulator.reset(getDevice()); - - mPointerIdBits.clear(); - - TouchInputMapper::reset(when); -} - -void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mMultiTouchMotionAccumulator.process(rawEvent); -} - -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { - size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); - size_t outCount = 0; - BitSet32 newPointerIdBits; - - for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = - mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { - continue; - } - - if (outCount >= MAX_POINTERS) { -#if DEBUG_POINTERS - ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " - "ignoring the rest.", - getDeviceName().string(), MAX_POINTERS); -#endif - break; // too many fingers! - } - - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); - outPointer.tiltX = 0; - outPointer.tiltY = 0; - - outPointer.toolType = inSlot->getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - } - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); - outPointer.isHovering = isHovering; - - // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; - } - } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); - } - } - - outCount += 1; - } - - mCurrentRawPointerData.pointerCount = outCount; - mPointerIdBits = newPointerIdBits; - - mMultiTouchMotionAccumulator.finishSync(); -} - -void MultiTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); - getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); - getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); - getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); - - if (mRawPointerAxes.trackingId.valid - && mRawPointerAxes.slot.valid - && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { - size_t slotCount = mRawPointerAxes.slot.maxValue + 1; - if (slotCount > MAX_SLOTS) { - ALOGW("MultiTouch Device %s reported %d slots but the framework " - "only supports a maximum of %d slots at this time.", - getDeviceName().string(), slotCount, MAX_SLOTS); - slotCount = MAX_SLOTS; - } - mMultiTouchMotionAccumulator.configure(getDevice(), - slotCount, true /*usingSlotsProtocol*/); - } else { - mMultiTouchMotionAccumulator.configure(getDevice(), - MAX_POINTERS, false /*usingSlotsProtocol*/); - } -} - -bool MultiTouchInputMapper::hasStylus() const { - return mMultiTouchMotionAccumulator.hasStylus() - || mTouchButtonAccumulator.hasStylus(); -} - - -// --- JoystickInputMapper --- - -JoystickInputMapper::JoystickInputMapper(InputDevice* device) : - InputMapper(device) { -} - -JoystickInputMapper::~JoystickInputMapper() { -} - -uint32_t JoystickInputMapper::getSources() { - return AINPUT_SOURCE_JOYSTICK; -} - -void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - for (size_t i = 0; i < mAxes.size(); i++) { - const Axis& axis = mAxes.valueAt(i); - addMotionRange(axis.axisInfo.axis, axis, info); - - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - addMotionRange(axis.axisInfo.highAxis, axis, info); - - } - } -} - -void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, - InputDeviceInfo* info) { - info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to register - * the old axes as duplicates of their corresponding new ones. */ - int32_t compatAxis = getCompatAxis(axisId); - if (compatAxis >= 0) { - info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - } -} - -/* A mapping from axes the joystick actually has to the axes that should be - * artificially created for compatibility purposes. - * Returns -1 if no compatibility axis is needed. */ -int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { - switch(axis) { - case AMOTION_EVENT_AXIS_LTRIGGER: - return AMOTION_EVENT_AXIS_BRAKE; - case AMOTION_EVENT_AXIS_RTRIGGER: - return AMOTION_EVENT_AXIS_GAS; - } - return -1; -} - -void JoystickInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Joystick Input Mapper:\n"); - - dump.append(INDENT3 "Axes:\n"); - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axisInfo.axis); - if (label) { - dump.appendFormat(INDENT4 "%s", label); - } else { - dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - label = getAxisLabel(axis.axisInfo.highAxis); - if (label) { - dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue); - } else { - dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis, - axis.axisInfo.splitValue); - } - } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { - dump.append(" (invert)"); - } - - dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, " - "highScale=%0.5f, highOffset=%0.5f\n", - axis.scale, axis.offset, axis.highScale, axis.highOffset); - dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " - "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", - mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, - axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); - } -} - -void JoystickInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Collect all axes. - for (int32_t abs = 0; abs <= ABS_MAX; abs++) { - if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) - & INPUT_DEVICE_CLASS_JOYSTICK)) { - continue; // axis must be claimed by a different device - } - - RawAbsoluteAxisInfo rawAxisInfo; - getAbsoluteAxisInfo(abs, &rawAxisInfo); - if (rawAxisInfo.valid) { - // Map axis. - AxisInfo axisInfo; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); - if (!explicitlyMapped) { - // Axis is not explicitly mapped, will choose a generic axis later. - axisInfo.mode = AxisInfo::MODE_NORMAL; - axisInfo.axis = -1; - } - - // Apply flat override. - int32_t rawFlat = axisInfo.flatOverride < 0 - ? rawAxisInfo.flat : axisInfo.flatOverride; - - // Calculate scaling factors and limits. - Axis axis; - if (axisInfo.mode == AxisInfo::MODE_SPLIT) { - float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); - float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, highScale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else if (isCenteredAxis(axisInfo.axis)) { - float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, offset, scale, offset, - -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else { - float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, scale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } - - // To eliminate noise while the joystick is at rest, filter out small variations - // in axis values up front. - axis.filter = axis.flat * 0.25f; - - mAxes.add(abs, axis); - } - } - - // If there are too many axes, start dropping them. - // Prefer to keep explicitly mapped axes. - if (mAxes.size() > PointerCoords::MAX_AXES) { - ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.", - getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES); - pruneAxes(true); - pruneAxes(false); - } - - // Assign generic axis ids to remaining axes. - int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (axis.axisInfo.axis < 0) { - while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 - && haveAxis(nextGenericAxisId)) { - nextGenericAxisId += 1; - } - - if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axisInfo.axis = nextGenericAxisId; - nextGenericAxisId += 1; - } else { - ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " - "have already been assigned to other axes.", - getDeviceName().string(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i--); - numAxes -= 1; - } - } - } - } -} - -bool JoystickInputMapper::haveAxis(int32_t axisId) { - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.axisInfo.axis == axisId - || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT - && axis.axisInfo.highAxis == axisId)) { - return true; - } - } - return false; -} - -void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { - size_t i = mAxes.size(); - while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { - if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { - continue; - } - ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", - getDeviceName().string(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i); - } -} - -bool JoystickInputMapper::isCenteredAxis(int32_t axis) { - switch (axis) { - case AMOTION_EVENT_AXIS_X: - case AMOTION_EVENT_AXIS_Y: - case AMOTION_EVENT_AXIS_Z: - case AMOTION_EVENT_AXIS_RX: - case AMOTION_EVENT_AXIS_RY: - case AMOTION_EVENT_AXIS_RZ: - case AMOTION_EVENT_AXIS_HAT_X: - case AMOTION_EVENT_AXIS_HAT_Y: - case AMOTION_EVENT_AXIS_ORIENTATION: - case AMOTION_EVENT_AXIS_RUDDER: - case AMOTION_EVENT_AXIS_WHEEL: - return true; - default: - return false; - } -} - -void JoystickInputMapper::reset(nsecs_t when) { - // Recenter all axes. - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - axis.resetValue(); - } - - InputMapper::reset(when); -} - -void JoystickInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_ABS: { - ssize_t index = mAxes.indexOfKey(rawEvent->code); - if (index >= 0) { - Axis& axis = mAxes.editValueAt(index); - float newValue, highNewValue; - switch (axis.axisInfo.mode) { - case AxisInfo::MODE_INVERT: - newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - case AxisInfo::MODE_SPLIT: - if (rawEvent->value < axis.axisInfo.splitValue) { - newValue = (axis.axisInfo.splitValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - } else if (rawEvent->value > axis.axisInfo.splitValue) { - newValue = 0.0f; - highNewValue = (rawEvent->value - axis.axisInfo.splitValue) - * axis.highScale + axis.highOffset; - } else { - newValue = 0.0f; - highNewValue = 0.0f; - } - break; - default: - newValue = rawEvent->value * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - } - axis.newValue = newValue; - axis.highNewValue = highNewValue; - } - break; - } - - case EV_SYN: - switch (rawEvent->code) { - case SYN_REPORT: - sync(rawEvent->when, false /*force*/); - break; - } - break; - } -} - -void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!filterAxes(force)) { - return; - } - - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = 0; - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, - axis.highCurrentValue); - } - } - - // Moving a joystick axis should not wake the device because joysticks can - // be fairly noisy even when not in use. On the other hand, pushing a gamepad - // button will likely wake the device. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - - NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); - getListener()->notifyMotion(&args); -} - -void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, - int32_t axis, float value) { - pointerCoords->setAxisValue(axis, value); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to produce - * values for the old axes as mirrors of the value of their corresponding - * new axes. */ - int32_t compatAxis = getCompatAxis(axis); - if (compatAxis >= 0) { - pointerCoords->setAxisValue(compatAxis, value); - } -} - -bool JoystickInputMapper::filterAxes(bool force) { - bool atLeastOneSignificantChange = force; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (force || hasValueChangedSignificantly(axis.filter, - axis.newValue, axis.currentValue, axis.min, axis.max)) { - axis.currentValue = axis.newValue; - atLeastOneSignificantChange = true; - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - if (force || hasValueChangedSignificantly(axis.filter, - axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { - axis.highCurrentValue = axis.highNewValue; - atLeastOneSignificantChange = true; - } - } - } - return atLeastOneSignificantChange; -} - -bool JoystickInputMapper::hasValueChangedSignificantly( - float filter, float newValue, float currentValue, float min, float max) { - if (newValue != currentValue) { - // Filter out small changes in value unless the value is converging on the axis - // bounds or center point. This is intended to reduce the amount of information - // sent to applications by particularly noisy joysticks (such as PS3). - if (fabs(newValue - currentValue) > filter - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { - return true; - } - } - return false; -} - -bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( - float filter, float newValue, float currentValue, float thresholdValue) { - float newDistance = fabs(newValue - thresholdValue); - if (newDistance < filter) { - float oldDistance = fabs(currentValue - thresholdValue); - if (newDistance < oldDistance) { - return true; - } - } - return false; -} - -} // namespace android diff --git a/widget/gonk/libui/InputReader.h b/widget/gonk/libui/InputReader.h deleted file mode 100644 index 5c790fdb8..000000000 --- a/widget/gonk/libui/InputReader.h +++ /dev/null @@ -1,1811 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_INPUT_READER_H -#define _UI_INPUT_READER_H - -#include "EventHub.h" -#include "PointerController.h" -#include "InputListener.h" - -#include "Input.h" -#include "VelocityControl.h" -#include "VelocityTracker.h" -#include <utils/KeyedVector.h> -#include <utils/threads.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/BitSet.h> - -#include <stddef.h> -#include <unistd.h> - -// Maximum supported size of a vibration pattern. -// Must be at least 2. -#define MAX_VIBRATE_PATTERN_SIZE 100 - -// Maximum allowable delay value in a vibration pattern before -// which the delay will be truncated. -#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL) - -namespace android { - -class InputDevice; -class InputMapper; - -/* - * Describes how coordinates are mapped on a physical display. - * See com.android.server.display.DisplayViewport. - */ -struct DisplayViewport { - int32_t displayId; // -1 if invalid - int32_t orientation; - int32_t logicalLeft; - int32_t logicalTop; - int32_t logicalRight; - int32_t logicalBottom; - int32_t physicalLeft; - int32_t physicalTop; - int32_t physicalRight; - int32_t physicalBottom; - int32_t deviceWidth; - int32_t deviceHeight; - - DisplayViewport() : - displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0), - logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0), - physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0), - deviceWidth(0), deviceHeight(0) { - } - - bool operator==(const DisplayViewport& other) const { - return displayId == other.displayId - && orientation == other.orientation - && logicalLeft == other.logicalLeft - && logicalTop == other.logicalTop - && logicalRight == other.logicalRight - && logicalBottom == other.logicalBottom - && physicalLeft == other.physicalLeft - && physicalTop == other.physicalTop - && physicalRight == other.physicalRight - && physicalBottom == other.physicalBottom - && deviceWidth == other.deviceWidth - && deviceHeight == other.deviceHeight; - } - - bool operator!=(const DisplayViewport& other) const { - return !(*this == other); - } - - inline bool isValid() const { - return displayId >= 0; - } - - void setNonDisplayViewport(int32_t width, int32_t height) { - displayId = ADISPLAY_ID_NONE; - orientation = DISPLAY_ORIENTATION_0; - logicalLeft = 0; - logicalTop = 0; - logicalRight = width; - logicalBottom = height; - physicalLeft = 0; - physicalTop = 0; - physicalRight = width; - physicalBottom = height; - deviceWidth = width; - deviceHeight = height; - } -}; - -/* - * Input reader configuration. - * - * Specifies various options that modify the behavior of the input reader. - */ -struct InputReaderConfiguration { - // Describes changes that have occurred. - enum { - // The pointer speed changed. - CHANGE_POINTER_SPEED = 1 << 0, - - // The pointer gesture control changed. - CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1, - - // The display size or orientation changed. - CHANGE_DISPLAY_INFO = 1 << 2, - - // The visible touches option changed. - CHANGE_SHOW_TOUCHES = 1 << 3, - - // The keyboard layouts must be reloaded. - CHANGE_KEYBOARD_LAYOUTS = 1 << 4, - - // The device name alias supplied by the may have changed for some devices. - CHANGE_DEVICE_ALIAS = 1 << 5, - - // All devices must be reopened. - CHANGE_MUST_REOPEN = 1 << 31, - }; - - // Gets the amount of time to disable virtual keys after the screen is touched - // in order to filter out accidental virtual key presses due to swiping gestures - // or taps near the edge of the display. May be 0 to disable the feature. - nsecs_t virtualKeyQuietTime; - - // The excluded device names for the platform. - // Devices with these names will be ignored. - Vector<String8> excludedDeviceNames; - - // Velocity control parameters for mouse pointer movements. - VelocityControlParameters pointerVelocityControlParameters; - - // Velocity control parameters for mouse wheel movements. - VelocityControlParameters wheelVelocityControlParameters; - - // True if pointer gestures are enabled. - bool pointerGesturesEnabled; - - // Quiet time between certain pointer gesture transitions. - // Time to allow for all fingers or buttons to settle into a stable state before - // starting a new gesture. - nsecs_t pointerGestureQuietInterval; - - // The minimum speed that a pointer must travel for us to consider switching the active - // touch pointer to it during a drag. This threshold is set to avoid switching due - // to noise from a finger resting on the touch pad (perhaps just pressing it down). - float pointerGestureDragMinSwitchSpeed; // in pixels per second - - // Tap gesture delay time. - // The time between down and up must be less than this to be considered a tap. - nsecs_t pointerGestureTapInterval; - - // Tap drag gesture delay time. - // The time between the previous tap's up and the next down must be less than - // this to be considered a drag. Otherwise, the previous tap is finished and a - // new tap begins. - // - // Note that the previous tap will be held down for this entire duration so this - // interval must be shorter than the long press timeout. - nsecs_t pointerGestureTapDragInterval; - - // The distance in pixels that the pointer is allowed to move from initial down - // to up and still be called a tap. - float pointerGestureTapSlop; // in pixels - - // Time after the first touch points go down to settle on an initial centroid. - // This is intended to be enough time to handle cases where the user puts down two - // fingers at almost but not quite exactly the same time. - nsecs_t pointerGestureMultitouchSettleInterval; - - // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when - // at least two pointers have moved at least this far from their starting place. - float pointerGestureMultitouchMinDistance; // in pixels - - // The transition from PRESS to SWIPE gesture mode can only occur when the - // cosine of the angle between the two vectors is greater than or equal to than this value - // which indicates that the vectors are oriented in the same direction. - // When the vectors are oriented in the exactly same direction, the cosine is 1.0. - // (In exactly opposite directions, the cosine is -1.0.) - float pointerGestureSwipeTransitionAngleCosine; - - // The transition from PRESS to SWIPE gesture mode can only occur when the - // fingers are no more than this far apart relative to the diagonal size of - // the touch pad. For example, a ratio of 0.5 means that the fingers must be - // no more than half the diagonal size of the touch pad apart. - float pointerGestureSwipeMaxWidthRatio; - - // The gesture movement speed factor relative to the size of the display. - // Movement speed applies when the fingers are moving in the same direction. - // Without acceleration, a full swipe of the touch pad diagonal in movement mode - // will cover this portion of the display diagonal. - float pointerGestureMovementSpeedRatio; - - // The gesture zoom speed factor relative to the size of the display. - // Zoom speed applies when the fingers are mostly moving relative to each other - // to execute a scale gesture or similar. - // Without acceleration, a full swipe of the touch pad diagonal in zoom mode - // will cover this portion of the display diagonal. - float pointerGestureZoomSpeedRatio; - - // True to show the location of touches on the touch screen as spots. - bool showTouches; - - InputReaderConfiguration() : - virtualKeyQuietTime(0), - pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), - wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), - pointerGesturesEnabled(true), - pointerGestureQuietInterval(100 * 1000000LL), // 100 ms - pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second - pointerGestureTapInterval(150 * 1000000LL), // 150 ms - pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms - pointerGestureTapSlop(10.0f), // 10 pixels - pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms - pointerGestureMultitouchMinDistance(15), // 15 pixels - pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees - pointerGestureSwipeMaxWidthRatio(0.25f), - pointerGestureMovementSpeedRatio(0.8f), - pointerGestureZoomSpeedRatio(0.3f), - showTouches(false) { } - - bool getDisplayInfo(bool external, DisplayViewport* outViewport) const; - void setDisplayInfo(bool external, const DisplayViewport& viewport); - -private: - DisplayViewport mInternalDisplay; - DisplayViewport mExternalDisplay; -}; - - -/* - * Input reader policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - * - * These methods must NOT re-enter the input reader since they may be called while - * holding the input reader lock. - */ -class InputReaderPolicyInterface : public virtual RefBase { -protected: - InputReaderPolicyInterface() { } - virtual ~InputReaderPolicyInterface() { } - -public: - /* Gets the input reader configuration. */ - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; - - /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ - virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0; - - /* Notifies the input reader policy that some input devices have changed - * and provides information about all current input devices. - */ - virtual void notifyInputDevicesChanged(const Vector<InputDeviceInfo>& inputDevices) = 0; - - /* Gets the keyboard layout for a particular input device. */ - virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0; - - /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; -}; - - -/* Processes raw input events and sends cooked event data to an input listener. */ -class InputReaderInterface : public virtual RefBase { -protected: - InputReaderInterface() { } - virtual ~InputReaderInterface() { } - -public: - /* Dumps the state of the input reader. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the processing loop. - * Nominally reads and processes one incoming message from the EventHub. - * - * This method should be called on the input reader thread. - */ - virtual void loopOnce() = 0; - - /* Gets information about all input devices. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices) = 0; - - /* Query current input state. */ - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) = 0; - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) = 0; - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw) = 0; - - /* Determine whether physical keys exist for the given framework-domain key codes. */ - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; - - /* Requests that a reconfiguration of all input devices. - * The changes flag is a bitfield that indicates what has changed and whether - * the input devices must all be reopened. */ - virtual void requestRefreshConfiguration(uint32_t changes) = 0; - - /* Controls the vibrator of a particular input device. */ - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) = 0; - virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; -}; - - -/* Internal interface used by individual input devices to access global input device state - * and parameters maintained by the input reader. - */ -class InputReaderContext { -public: - InputReaderContext() { } - virtual ~InputReaderContext() { } - - virtual void updateGlobalMetaState() = 0; - virtual int32_t getGlobalMetaState() = 0; - - virtual void disableVirtualKeysUntil(nsecs_t time) = 0; - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; - - virtual void fadePointer() = 0; - - virtual void requestTimeoutAtTime(nsecs_t when) = 0; - virtual int32_t bumpGeneration() = 0; - - virtual InputReaderPolicyInterface* getPolicy() = 0; - virtual InputListenerInterface* getListener() = 0; - virtual EventHubInterface* getEventHub() = 0; -}; - - -/* The input reader reads raw event data from the event hub and processes it into input events - * that it sends to the input listener. Some functions of the input reader, such as early - * event filtering in low power states, are controlled by a separate policy object. - * - * The InputReader owns a collection of InputMappers. Most of the work it does happens - * on the input reader thread but the InputReader can receive queries from other system - * components running on arbitrary threads. To keep things manageable, the InputReader - * uses a single Mutex to guard its state. The Mutex may be held while calling into the - * EventHub or the InputReaderPolicy but it is never held while calling into the - * InputListener. - */ -class InputReader : public InputReaderInterface { -public: - InputReader(const sp<EventHubInterface>& eventHub, - const sp<InputReaderPolicyInterface>& policy, - const sp<InputListenerInterface>& listener); - virtual ~InputReader(); - - virtual void dump(String8& dump); - virtual void monitor(); - - virtual void loopOnce(); - - virtual void getInputDevices(Vector<InputDeviceInfo>& outInputDevices); - - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode); - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode); - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw); - - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); - - virtual void requestRefreshConfiguration(uint32_t changes); - - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t deviceId, int32_t token); - -protected: - // These members are protected so they can be instrumented by test cases. - virtual InputDevice* createDeviceLocked(int32_t deviceId, - const InputDeviceIdentifier& identifier, uint32_t classes); - - class ContextImpl : public InputReaderContext { - InputReader* mReader; - - public: - ContextImpl(InputReader* reader); - - virtual void updateGlobalMetaState(); - virtual int32_t getGlobalMetaState(); - virtual void disableVirtualKeysUntil(nsecs_t time); - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - virtual void fadePointer(); - virtual void requestTimeoutAtTime(nsecs_t when); - virtual int32_t bumpGeneration(); - virtual InputReaderPolicyInterface* getPolicy(); - virtual InputListenerInterface* getListener(); - virtual EventHubInterface* getEventHub(); - } mContext; - - friend class ContextImpl; - -private: - Mutex mLock; - - Condition mReaderIsAliveCondition; - - sp<EventHubInterface> mEventHub; - sp<InputReaderPolicyInterface> mPolicy; - sp<QueuedInputListener> mQueuedListener; - - InputReaderConfiguration mConfig; - - // The event queue. - static const int EVENT_BUFFER_SIZE = 256; - RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - - KeyedVector<int32_t, InputDevice*> mDevices; - - // low-level input event decoding and device management - void processEventsLocked(const RawEvent* rawEvents, size_t count); - - void addDeviceLocked(nsecs_t when, int32_t deviceId); - void removeDeviceLocked(nsecs_t when, int32_t deviceId); - void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); - void timeoutExpiredLocked(nsecs_t when); - - void handleConfigurationChangedLocked(nsecs_t when); - - int32_t mGlobalMetaState; - void updateGlobalMetaStateLocked(); - int32_t getGlobalMetaStateLocked(); - - void fadePointerLocked(); - - int32_t mGeneration; - int32_t bumpGenerationLocked(); - - void getInputDevicesLocked(Vector<InputDeviceInfo>& outInputDevices); - - nsecs_t mDisableVirtualKeysTimeout; - void disableVirtualKeysUntilLocked(nsecs_t time); - bool shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - - nsecs_t mNextTimeout; - void requestTimeoutAtTimeLocked(nsecs_t when); - - uint32_t mConfigurationChangesToRefresh; - void refreshConfigurationLocked(uint32_t changes); - - // state queries - typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); -}; - - -/* Reads raw events from the event hub and processes them, endlessly. */ -class InputReaderThread : public Thread { -public: - InputReaderThread(const sp<InputReaderInterface>& reader); - virtual ~InputReaderThread(); - -private: - uint32_t mFoo; - sp<InputReaderInterface> mReader; - - virtual bool threadLoop(); -}; - - -/* Represents the state of a single input device. */ -class InputDevice { -public: - InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - const InputDeviceIdentifier& identifier, uint32_t classes); - ~InputDevice(); - - inline InputReaderContext* getContext() { return mContext; } - inline int32_t getId() { return mId; } - inline int32_t getGeneration() { return mGeneration; } - inline const String8& getName() { return mIdentifier.name; } - inline uint32_t getClasses() { return mClasses; } - inline uint32_t getSources() { return mSources; } - - inline bool isExternal() { return mIsExternal; } - inline void setExternal(bool external) { mIsExternal = external; } - - inline bool isIgnored() { return mMappers.isEmpty(); } - - void dump(String8& dump); - void addMapper(InputMapper* mapper); - void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - void reset(nsecs_t when); - void process(const RawEvent* rawEvents, size_t count); - void timeoutExpired(nsecs_t when); - - void getDeviceInfo(InputDeviceInfo* outDeviceInfo); - int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - void cancelVibrate(int32_t token); - - int32_t getMetaState(); - - void fadePointer(); - - void bumpGeneration(); - - void notifyReset(nsecs_t when); - - inline const PropertyMap& getConfiguration() { return mConfiguration; } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - bool hasKey(int32_t code) { - return getEventHub()->hasScanCode(mId, code); - } - - bool hasAbsoluteAxis(int32_t code) { - RawAbsoluteAxisInfo info; - getEventHub()->getAbsoluteAxisInfo(mId, code, &info); - return info.valid; - } - - bool isKeyPressed(int32_t code) { - return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; - } - - int32_t getAbsoluteAxisValue(int32_t code) { - int32_t value; - getEventHub()->getAbsoluteAxisValue(mId, code, &value); - return value; - } - -private: - InputReaderContext* mContext; - int32_t mId; - int32_t mGeneration; - InputDeviceIdentifier mIdentifier; - String8 mAlias; - uint32_t mClasses; - - Vector<InputMapper*> mMappers; - - uint32_t mSources; - bool mIsExternal; - bool mDropUntilNextSync; - - typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); - - PropertyMap mConfiguration; -}; - - -/* Keeps track of the state of mouse or touch pad buttons. */ -class CursorButtonAccumulator { -public: - CursorButtonAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - -private: - bool mBtnLeft; - bool mBtnRight; - bool mBtnMiddle; - bool mBtnBack; - bool mBtnSide; - bool mBtnForward; - bool mBtnExtra; - bool mBtnTask; - - void clearButtons(); -}; - - -/* Keeps track of cursor movements. */ - -class CursorMotionAccumulator { -public: - CursorMotionAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - -private: - int32_t mRelX; - int32_t mRelY; - - void clearRelativeAxes(); -}; - - -/* Keeps track of cursor scrolling motions. */ - -class CursorScrollAccumulator { -public: - CursorScrollAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline bool haveRelativeVWheel() const { return mHaveRelWheel; } - inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - inline int32_t getRelativeVWheel() const { return mRelWheel; } - inline int32_t getRelativeHWheel() const { return mRelHWheel; } - -private: - bool mHaveRelWheel; - bool mHaveRelHWheel; - - int32_t mRelX; - int32_t mRelY; - int32_t mRelWheel; - int32_t mRelHWheel; - - void clearRelativeAxes(); -}; - - -/* Keeps track of the state of touch, stylus and tool buttons. */ -class TouchButtonAccumulator { -public: - TouchButtonAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - int32_t getToolType() const; - bool isToolActive() const; - bool isHovering() const; - bool hasStylus() const; - -private: - bool mHaveBtnTouch; - bool mHaveStylus; - - bool mBtnTouch; - bool mBtnStylus; - bool mBtnStylus2; - bool mBtnToolFinger; - bool mBtnToolPen; - bool mBtnToolRubber; - bool mBtnToolBrush; - bool mBtnToolPencil; - bool mBtnToolAirbrush; - bool mBtnToolMouse; - bool mBtnToolLens; - bool mBtnToolDoubleTap; - bool mBtnToolTripleTap; - bool mBtnToolQuadTap; - - void clearButtons(); -}; - - -/* Raw axis information from the driver. */ -struct RawPointerAxes { - RawAbsoluteAxisInfo x; - RawAbsoluteAxisInfo y; - RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo touchMajor; - RawAbsoluteAxisInfo touchMinor; - RawAbsoluteAxisInfo toolMajor; - RawAbsoluteAxisInfo toolMinor; - RawAbsoluteAxisInfo orientation; - RawAbsoluteAxisInfo distance; - RawAbsoluteAxisInfo tiltX; - RawAbsoluteAxisInfo tiltY; - RawAbsoluteAxisInfo trackingId; - RawAbsoluteAxisInfo slot; - - RawPointerAxes(); - void clear(); -}; - - -/* Raw data for a collection of pointers including a pointer id mapping table. */ -struct RawPointerData { - struct Pointer { - uint32_t id; - int32_t x; - int32_t y; - int32_t pressure; - int32_t touchMajor; - int32_t touchMinor; - int32_t toolMajor; - int32_t toolMinor; - int32_t orientation; - int32_t distance; - int32_t tiltX; - int32_t tiltY; - int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant - bool isHovering; - }; - - uint32_t pointerCount; - Pointer pointers[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - RawPointerData(); - void clear(); - void copyFrom(const RawPointerData& other); - void getCentroidOfTouchingPointers(float* outX, float* outY) const; - - inline void markIdBit(uint32_t id, bool isHovering) { - if (isHovering) { - hoveringIdBits.markBit(id); - } else { - touchingIdBits.markBit(id); - } - } - - inline void clearIdBits() { - hoveringIdBits.clear(); - touchingIdBits.clear(); - } - - inline const Pointer& pointerForId(uint32_t id) const { - return pointers[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return pointers[pointerIndex].isHovering; - } -}; - - -/* Cooked data for a collection of pointers including a pointer id mapping table. */ -struct CookedPointerData { - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - CookedPointerData(); - void clear(); - void copyFrom(const CookedPointerData& other); - - inline const PointerCoords& pointerCoordsForId(uint32_t id) const { - return pointerCoords[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); - } -}; - - -/* Keeps track of the state of single-touch protocol. */ -class SingleTouchMotionAccumulator { -public: - SingleTouchMotionAccumulator(); - - void process(const RawEvent* rawEvent); - void reset(InputDevice* device); - - inline int32_t getAbsoluteX() const { return mAbsX; } - inline int32_t getAbsoluteY() const { return mAbsY; } - inline int32_t getAbsolutePressure() const { return mAbsPressure; } - inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } - inline int32_t getAbsoluteDistance() const { return mAbsDistance; } - inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } - inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } - -private: - int32_t mAbsX; - int32_t mAbsY; - int32_t mAbsPressure; - int32_t mAbsToolWidth; - int32_t mAbsDistance; - int32_t mAbsTiltX; - int32_t mAbsTiltY; - - void clearAbsoluteAxes(); -}; - - -/* Keeps track of the state of multi-touch protocol. */ -class MultiTouchMotionAccumulator { -public: - class Slot { - public: - inline bool isInUse() const { return mInUse; } - inline int32_t getX() const { return mAbsMTPositionX; } - inline int32_t getY() const { return mAbsMTPositionY; } - inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } - inline int32_t getTouchMinor() const { - return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } - inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } - inline int32_t getToolMinor() const { - return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } - inline int32_t getOrientation() const { return mAbsMTOrientation; } - inline int32_t getTrackingId() const { return mAbsMTTrackingId; } - inline int32_t getPressure() const { return mAbsMTPressure; } - inline int32_t getDistance() const { return mAbsMTDistance; } - inline int32_t getToolType() const; - - private: - friend class MultiTouchMotionAccumulator; - - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); - }; - - MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); - - void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); - void reset(InputDevice* device); - void process(const RawEvent* rawEvent); - void finishSync(); - bool hasStylus() const; - - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } - -private: - int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; - bool mUsingSlotsProtocol; - bool mHaveStylus; - - void clearSlots(int32_t initialSlot); -}; - - -/* An input mapper transforms raw input events into cooked event data. - * A single input device can have multiple associated input mappers in order to interpret - * different classes of events. - * - * InputMapper lifecycle: - * - create - * - configure with 0 changes - * - reset - * - process, process, process (may occasionally reconfigure with non-zero changes or reset) - * - reset - * - destroy - */ -class InputMapper { -public: - InputMapper(InputDevice* device); - virtual ~InputMapper(); - - inline InputDevice* getDevice() { return mDevice; } - inline int32_t getDeviceId() { return mDevice->getId(); } - inline const String8 getDeviceName() { return mDevice->getName(); } - inline InputReaderContext* getContext() { return mContext; } - inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } - inline InputListenerInterface* getListener() { return mContext->getListener(); } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - virtual uint32_t getSources() = 0; - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent) = 0; - virtual void timeoutExpired(nsecs_t when); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - - virtual int32_t getMetaState(); - - virtual void fadePointer(); - -protected: - InputDevice* mDevice; - InputReaderContext* mContext; - - status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); - void bumpGeneration(); - - static void dumpRawAbsoluteAxisInfo(String8& dump, - const RawAbsoluteAxisInfo& axis, const char* name); -}; - - -class SwitchInputMapper : public InputMapper { -public: - SwitchInputMapper(InputDevice* device); - virtual ~SwitchInputMapper(); - - virtual uint32_t getSources(); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - -private: - uint32_t mUpdatedSwitchValues; - uint32_t mUpdatedSwitchMask; - - void processSwitch(int32_t switchCode, int32_t switchValue); - void sync(nsecs_t when); -}; - - -class VibratorInputMapper : public InputMapper { -public: - VibratorInputMapper(InputDevice* device); - virtual ~VibratorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void process(const RawEvent* rawEvent); - - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void timeoutExpired(nsecs_t when); - virtual void dump(String8& dump); - -private: - bool mVibrating; - nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; - size_t mPatternSize; - ssize_t mRepeat; - int32_t mToken; - ssize_t mIndex; - nsecs_t mNextStepTime; - - void nextStep(); - void stopVibrating(); -}; - - -class KeyboardInputMapper : public InputMapper { -public: - KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); - virtual ~KeyboardInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual int32_t getMetaState(); - -private: - struct KeyDown { - int32_t keyCode; - int32_t scanCode; - }; - - uint32_t mSource; - int32_t mKeyboardType; - - int32_t mOrientation; // orientation for dpad keys - - Vector<KeyDown> mKeyDowns; // keys that are down - int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down - - int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none - - struct LedState { - bool avail; // led is available - bool on; // we think the led is currently on - }; - LedState mCapsLockLedState; - LedState mNumLockLedState; - LedState mScrollLockLedState; - - // Immutable configuration parameters. - struct Parameters { - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - void configureParameters(); - void dumpParameters(String8& dump); - - bool isKeyboardOrGamepadKey(int32_t scanCode); - - void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, - uint32_t policyFlags); - - ssize_t findKeyDown(int32_t scanCode); - - void resetLedState(); - void initializeLedState(LedState& ledState, int32_t led); - void updateLedState(bool reset); - void updateLedStateForModifier(LedState& ledState, int32_t led, - int32_t modifier, bool reset); -}; - - -class CursorInputMapper : public InputMapper { -public: - CursorInputMapper(InputDevice* device); - virtual ~CursorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - - virtual void fadePointer(); - -private: - // Amount that trackball needs to move in order to generate a key event. - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; - - // Immutable configuration parameters. - struct Parameters { - enum Mode { - MODE_POINTER, - MODE_NAVIGATION, - }; - - Mode mode; - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - CursorButtonAccumulator mCursorButtonAccumulator; - CursorMotionAccumulator mCursorMotionAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - - int32_t mSource; - float mXScale; - float mYScale; - float mXPrecision; - float mYPrecision; - - float mVWheelScale; - float mHWheelScale; - - // Velocity controls for mouse pointer and wheel movements. - // The controls for X and Y wheel movements are separate to keep them decoupled. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - int32_t mOrientation; - - sp<PointerControllerInterface> mPointerController; - - int32_t mButtonState; - nsecs_t mDownTime; - - void configureParameters(); - void dumpParameters(String8& dump); - - void sync(nsecs_t when); -}; - - -class TouchInputMapper : public InputMapper { -public: - TouchInputMapper(InputDevice* device); - virtual ~TouchInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual void fadePointer(); - virtual void timeoutExpired(nsecs_t when); - -protected: - CursorButtonAccumulator mCursorButtonAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; - - struct VirtualKey { - int32_t keyCode; - int32_t scanCode; - uint32_t flags; - - // computed hit box, specified in touch screen coords based on known display size - int32_t hitLeft; - int32_t hitTop; - int32_t hitRight; - int32_t hitBottom; - - inline bool isHit(int32_t x, int32_t y) const { - return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; - } - }; - - // Input sources and device mode. - uint32_t mSource; - - enum DeviceMode { - DEVICE_MODE_DISABLED, // input is disabled - DEVICE_MODE_DIRECT, // direct mapping (touchscreen) - DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) - DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - DEVICE_MODE_POINTER, // pointer mapping (pointer) - }; - DeviceMode mDeviceMode; - - // The reader's configuration. - InputReaderConfiguration mConfig; - - // Immutable configuration parameters. - struct Parameters { - enum DeviceType { - DEVICE_TYPE_TOUCH_SCREEN, - DEVICE_TYPE_TOUCH_PAD, - DEVICE_TYPE_TOUCH_NAVIGATION, - DEVICE_TYPE_POINTER, - }; - - DeviceType deviceType; - bool hasAssociatedDisplay; - bool associatedDisplayIsExternal; - bool orientationAware; - - enum GestureMode { - GESTURE_MODE_POINTER, - GESTURE_MODE_SPOTS, - }; - GestureMode gestureMode; - } mParameters; - - // Immutable calibration parameters in parsed form. - struct Calibration { - // Size - enum SizeCalibration { - SIZE_CALIBRATION_DEFAULT, - SIZE_CALIBRATION_NONE, - SIZE_CALIBRATION_GEOMETRIC, - SIZE_CALIBRATION_DIAMETER, - SIZE_CALIBRATION_BOX, - SIZE_CALIBRATION_AREA, - }; - - SizeCalibration sizeCalibration; - - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; - - // Pressure - enum PressureCalibration { - PRESSURE_CALIBRATION_DEFAULT, - PRESSURE_CALIBRATION_NONE, - PRESSURE_CALIBRATION_PHYSICAL, - PRESSURE_CALIBRATION_AMPLITUDE, - }; - - PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; - - // Orientation - enum OrientationCalibration { - ORIENTATION_CALIBRATION_DEFAULT, - ORIENTATION_CALIBRATION_NONE, - ORIENTATION_CALIBRATION_INTERPOLATED, - ORIENTATION_CALIBRATION_VECTOR, - }; - - OrientationCalibration orientationCalibration; - - // Distance - enum DistanceCalibration { - DISTANCE_CALIBRATION_DEFAULT, - DISTANCE_CALIBRATION_NONE, - DISTANCE_CALIBRATION_SCALED, - }; - - DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; - - enum CoverageCalibration { - COVERAGE_CALIBRATION_DEFAULT, - COVERAGE_CALIBRATION_NONE, - COVERAGE_CALIBRATION_BOX, - }; - - CoverageCalibration coverageCalibration; - - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; - } - if (haveSizeBias) { - *outSize += sizeBias; - } - } - } mCalibration; - - // Raw pointer axis information from the driver. - RawPointerAxes mRawPointerAxes; - - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; - - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; - - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; - - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; - - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; - - // True if we sent a HOVER_ENTER event. - bool mSentHoverEnter; - - // The time the primary pointer last went down. - nsecs_t mDownTime; - - // The pointer controller, or null if the device is not a pointer. - sp<PointerControllerInterface> mPointerController; - - Vector<VirtualKey> mVirtualKeys; - - virtual void configureParameters(); - virtual void dumpParameters(String8& dump); - virtual void configureRawPointerAxes(); - virtual void dumpRawPointerAxes(String8& dump); - virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(String8& dump); - virtual void configureVirtualKeys(); - virtual void dumpVirtualKeys(String8& dump); - virtual void parseCalibration(); - virtual void resolveCalibration(); - virtual void dumpCalibration(String8& dump); - virtual bool hasStylus() const = 0; - - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; - -private: - // The current viewport. - // The components of the viewport are specified in the display's rotated orientation. - DisplayViewport mViewport; - - // The surface orientation, width and height set by configureSurface(). - // The width and height are derived from the viewport but are specified - // in the natural orientation. - // The surface origin specifies how the surface coordinates should be translated - // to align with the logical display coordinate space. - // The orientation may be different from the viewport orientation as it specifies - // the rotation of the surface coordinates required to produce the viewport's - // requested orientation, so it will depend on whether the device is orientation aware. - int32_t mSurfaceWidth; - int32_t mSurfaceHeight; - int32_t mSurfaceLeft; - int32_t mSurfaceTop; - int32_t mSurfaceOrientation; - - // Translation and scaling factors, orientation-independent. - float mXTranslate; - float mXScale; - float mXPrecision; - - float mYTranslate; - float mYScale; - float mYPrecision; - - float mGeometricScale; - - float mPressureScale; - - float mSizeScale; - - float mOrientationScale; - - float mDistanceScale; - - bool mHaveTilt; - float mTiltXCenter; - float mTiltXScale; - float mTiltYCenter; - float mTiltYScale; - - // Oriented motion ranges for input device info. - struct OrientedRanges { - InputDeviceInfo::MotionRange x; - InputDeviceInfo::MotionRange y; - InputDeviceInfo::MotionRange pressure; - - bool haveSize; - InputDeviceInfo::MotionRange size; - - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; - - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; - - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; - - bool haveDistance; - InputDeviceInfo::MotionRange distance; - - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { - clear(); - } - - void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; - } - } mOrientedRanges; - - // Oriented dimensions and precision. - float mOrientedXPrecision; - float mOrientedYPrecision; - - struct CurrentVirtualKeyState { - bool down; - bool ignored; - nsecs_t downTime; - int32_t keyCode; - int32_t scanCode; - } mCurrentVirtualKey; - - // Scale factor for gesture or mouse based pointer movements. - float mPointerXMovementScale; - float mPointerYMovementScale; - - // Scale factor for gesture based zooming and other freeform motions. - float mPointerXZoomScale; - float mPointerYZoomScale; - - // The maximum swipe width. - float mPointerGestureMaxSwipeWidth; - - struct PointerDistanceHeapElement { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance - }; - - enum PointerUsage { - POINTER_USAGE_NONE, - POINTER_USAGE_GESTURES, - POINTER_USAGE_STYLUS, - POINTER_USAGE_MOUSE, - }; - PointerUsage mPointerUsage; - - struct PointerGesture { - enum Mode { - // No fingers, button is not pressed. - // Nothing happening. - NEUTRAL, - - // No fingers, button is not pressed. - // Tap detected. - // Emits DOWN and UP events at the pointer location. - TAP, - - // Exactly one finger dragging following a tap. - // Pointer follows the active finger. - // Emits DOWN, MOVE and UP events at the pointer location. - // - // Detect double-taps when the finger goes up while in TAP_DRAG mode. - TAP_DRAG, - - // Button is pressed. - // Pointer follows the active finger if there is one. Other fingers are ignored. - // Emits DOWN, MOVE and UP events at the pointer location. - BUTTON_CLICK_OR_DRAG, - - // Exactly one finger, button is not pressed. - // Pointer follows the active finger. - // Emits HOVER_MOVE events at the pointer location. - // - // Detect taps when the finger goes up while in HOVER mode. - HOVER, - - // Exactly two fingers but neither have moved enough to clearly indicate - // whether a swipe or freeform gesture was intended. We consider the - // pointer to be pressed so this enables clicking or long-pressing on buttons. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. - PRESS, - - // Exactly two fingers moving in the same direction, button is not pressed. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single pointer coordinate that - // follows the midpoint between both fingers. - SWIPE, - - // Two or more fingers moving in arbitrary directions, button is not pressed. - // Pointer does not move. - // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow - // each finger individually relative to the initial centroid of the finger. - FREEFORM, - - // Waiting for quiet time to end before starting the next gesture. - QUIET, - }; - - // Time the first finger went down. - nsecs_t firstTouchTime; - - // The active pointer id from the raw touch data. - int32_t activeTouchId; // -1 if none - - // The active pointer id from the gesture last delivered to the application. - int32_t activeGestureId; // -1 if none - - // Pointer coords and ids for the current and previous pointer gesture. - Mode currentGestureMode; - BitSet32 currentGestureIdBits; - uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties currentGestureProperties[MAX_POINTERS]; - PointerCoords currentGestureCoords[MAX_POINTERS]; - - Mode lastGestureMode; - BitSet32 lastGestureIdBits; - uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties lastGestureProperties[MAX_POINTERS]; - PointerCoords lastGestureCoords[MAX_POINTERS]; - - // Time the pointer gesture last went down. - nsecs_t downTime; - - // Time when the pointer went down for a TAP. - nsecs_t tapDownTime; - - // Time when the pointer went up for a TAP. - nsecs_t tapUpTime; - - // Location of initial tap. - float tapX, tapY; - - // Time we started waiting for quiescence. - nsecs_t quietTime; - - // Reference points for multitouch gestures. - float referenceTouchX; // reference touch X/Y coordinates in surface units - float referenceTouchY; - float referenceGestureX; // reference gesture X/Y coordinates in pixels - float referenceGestureY; - - // Distance that each pointer has traveled which has not yet been - // subsumed into the reference gesture position. - BitSet32 referenceIdBits; - struct Delta { - float dx, dy; - }; - Delta referenceDeltas[MAX_POINTER_ID + 1]; - - // Describes how touch ids are mapped to gesture ids for freeform gestures. - uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; - - // A velocity tracker for determining whether to switch active pointers during drags. - VelocityTracker velocityTracker; - - void reset() { - firstTouchTime = LLONG_MIN; - activeTouchId = -1; - activeGestureId = -1; - currentGestureMode = NEUTRAL; - currentGestureIdBits.clear(); - lastGestureMode = NEUTRAL; - lastGestureIdBits.clear(); - downTime = 0; - velocityTracker.clear(); - resetTap(); - resetQuietTime(); - } - - void resetTap() { - tapDownTime = LLONG_MIN; - tapUpTime = LLONG_MIN; - } - - void resetQuietTime() { - quietTime = LLONG_MIN; - } - } mPointerGesture; - - struct PointerSimple { - PointerCoords currentCoords; - PointerProperties currentProperties; - PointerCoords lastCoords; - PointerProperties lastProperties; - - // True if the pointer is down. - bool down; - - // True if the pointer is hovering. - bool hovering; - - // Time the pointer last went down. - nsecs_t downTime; - - void reset() { - currentCoords.clear(); - currentProperties.clear(); - lastCoords.clear(); - lastProperties.clear(); - down = false; - hovering = false; - downTime = 0; - } - } mPointerSimple; - - // The pointer and scroll velocity controls. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - void sync(nsecs_t when); - - bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); - void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags); - - void dispatchTouches(nsecs_t when, uint32_t policyFlags); - void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); - void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); - void cookPointerData(); - - void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); - void abortPointerUsage(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); - void abortPointerGestures(nsecs_t when, uint32_t policyFlags); - bool preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, - bool isTimeout); - - void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); - void abortPointerStylus(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); - void abortPointerMouse(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering); - void abortPointerSimple(nsecs_t when, uint32_t policyFlags); - - // Dispatches a motion event. - // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the - // method will take care of setting the index and transmuting the action to DOWN or UP - // it is the first / last pointer to go down / up. - void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); - - // Updates pointer coords and properties for pointers with specified ids that have moved. - // Returns true if any of them changed. - bool updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, - const uint32_t* outIdToIndex, BitSet32 idBits) const; - - bool isPointInsideSurface(int32_t x, int32_t y); - const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - - void assignPointerIds(); -}; - - -class SingleTouchInputMapper : public TouchInputMapper { -public: - SingleTouchInputMapper(InputDevice* device); - virtual ~SingleTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; -}; - - -class MultiTouchInputMapper : public TouchInputMapper { -public: - MultiTouchInputMapper(InputDevice* device); - virtual ~MultiTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; - - // Specifies the pointer id bits that are in use, and their associated tracking id. - BitSet32 mPointerIdBits; - int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; -}; - - -class JoystickInputMapper : public InputMapper { -public: - JoystickInputMapper(InputDevice* device); - virtual ~JoystickInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - struct Axis { - RawAbsoluteAxisInfo rawAxisInfo; - AxisInfo axisInfo; - - bool explicitlyMapped; // true if the axis was explicitly assigned an axis id - - float scale; // scale factor from raw to normalized values - float offset; // offset to add after scaling for normalization - float highScale; // scale factor from raw to normalized values of high split - float highOffset; // offset to add after scaling for normalization of high split - - float min; // normalized inclusive minimum - float max; // normalized inclusive maximum - float flat; // normalized flat region size - float fuzz; // normalized error tolerance - float resolution; // normalized resolution in units/mm - - float filter; // filter out small variations of this size - float currentValue; // current value - float newValue; // most recent value - float highCurrentValue; // current value of high split - float highNewValue; // most recent value of high split - - void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, - bool explicitlyMapped, float scale, float offset, - float highScale, float highOffset, - float min, float max, float flat, float fuzz, float resolution) { - this->rawAxisInfo = rawAxisInfo; - this->axisInfo = axisInfo; - this->explicitlyMapped = explicitlyMapped; - this->scale = scale; - this->offset = offset; - this->highScale = highScale; - this->highOffset = highOffset; - this->min = min; - this->max = max; - this->flat = flat; - this->fuzz = fuzz; - this->resolution = resolution; - this->filter = 0; - resetValue(); - } - - void resetValue() { - this->currentValue = 0; - this->newValue = 0; - this->highCurrentValue = 0; - this->highNewValue = 0; - } - }; - - // Axes indexed by raw ABS_* axis index. - KeyedVector<int32_t, Axis> mAxes; - - void sync(nsecs_t when, bool force); - - bool haveAxis(int32_t axisId); - void pruneAxes(bool ignoreExplicitlyMappedAxes); - bool filterAxes(bool force); - - static bool hasValueChangedSignificantly(float filter, - float newValue, float currentValue, float min, float max); - static bool hasMovedNearerToValueWithinFilteredRange(float filter, - float newValue, float currentValue, float thresholdValue); - - static bool isCenteredAxis(int32_t axis); - static int32_t getCompatAxis(int32_t axis); - - static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); - static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, - float value); -}; - -} // namespace android - -#endif // _UI_INPUT_READER_H diff --git a/widget/gonk/libui/InputTransport.cpp b/widget/gonk/libui/InputTransport.cpp deleted file mode 100644 index 3f0fcb047..000000000 --- a/widget/gonk/libui/InputTransport.cpp +++ /dev/null @@ -1,957 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// -// Provides a shared memory transport for input events. -// -#define LOG_TAG "InputTransport" - -//#define LOG_NDEBUG 0 - -// Log debug messages about channel messages (send message, receive message) -#define DEBUG_CHANNEL_MESSAGES 0 - -// Log debug messages whenever InputChannel objects are created/destroyed -#define DEBUG_CHANNEL_LIFECYCLE 0 - -// Log debug messages about transport actions -#define DEBUG_TRANSPORT_ACTIONS 0 - -// Log debug messages about touch event resampling -#define DEBUG_RESAMPLING 0 - - -#include "cutils_log.h" -#include <cutils/properties.h> -#include <errno.h> -#include <fcntl.h> -#include "InputTransport.h" -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <math.h> - - -namespace android { - -// Socket buffer size. The default is typically about 128KB, which is much larger than -// we really need. So we make it smaller. It just needs to be big enough to hold -// a few dozen large multi-finger motion events in the case where an application gets -// behind processing touches. -static const size_t SOCKET_BUFFER_SIZE = 32 * 1024; - -// Nanoseconds per milliseconds. -static const nsecs_t NANOS_PER_MS = 1000000; - -// Latency added during resampling. A few milliseconds doesn't hurt much but -// reduces the impact of mispredicted touch positions. -static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS; - -// Minimum time difference between consecutive samples before attempting to resample. -static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS; - -// Maximum time to predict forward from the last known state, to avoid predicting too -// far into the future. This time is further bounded by 50% of the last time delta. -static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; - -template<typename T> -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -inline static float lerp(float a, float b, float alpha) { - return a + alpha * (b - a); -} - -// --- InputMessage --- - -bool InputMessage::isValid(size_t actualSize) const { - if (size() == actualSize) { - switch (header.type) { - case TYPE_KEY: - return true; - case TYPE_MOTION: - return body.motion.pointerCount > 0 - && body.motion.pointerCount <= MAX_POINTERS; - case TYPE_FINISHED: - return true; - } - } - return false; -} - -size_t InputMessage::size() const { - switch (header.type) { - case TYPE_KEY: - return sizeof(Header) + body.key.size(); - case TYPE_MOTION: - return sizeof(Header) + body.motion.size(); - case TYPE_FINISHED: - return sizeof(Header) + body.finished.size(); - } - return sizeof(Header); -} - - -// --- InputChannel --- - -InputChannel::InputChannel(const String8& name, int fd) : - mName(name), mFd(fd) { -#if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel constructed: name='%s', fd=%d", - mName.string(), fd); -#endif - - int result = fcntl(mFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " - "non-blocking. errno=%d", mName.string(), errno); -} - -InputChannel::~InputChannel() { -#if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel destroyed: name='%s', fd=%d", - mName.string(), mFd); -#endif - - ::close(mFd); -} - -status_t InputChannel::openInputChannelPair(const String8& name, - sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) { - int sockets[2]; - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { - status_t result = -errno; - ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", - name.string(), errno); - outServerChannel.clear(); - outClientChannel.clear(); - return result; - } - - int bufferSize = SOCKET_BUFFER_SIZE; - setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); - setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); - setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - - String8 serverChannelName = name; - serverChannelName.append(" (server)"); - outServerChannel = new InputChannel(serverChannelName, sockets[0]); - - String8 clientChannelName = name; - clientChannelName.append(" (client)"); - outClientChannel = new InputChannel(clientChannelName, sockets[1]); - return OK; -} - -status_t InputChannel::sendMessage(const InputMessage* msg) { - size_t msgLength = msg->size(); - ssize_t nWrite; - do { - nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite < 0) { - int error = errno; -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), - msg->header.type, error); -#endif - if (error == EAGAIN || error == EWOULDBLOCK) { - return WOULD_BLOCK; - } - if (error == EPIPE || error == ENOTCONN) { - return DEAD_OBJECT; - } - return -error; - } - - if (size_t(nWrite) != msgLength) { -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", - mName.string(), msg->header.type); -#endif - return DEAD_OBJECT; - } - -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); -#endif - return OK; -} - -status_t InputChannel::receiveMessage(InputMessage* msg) { - ssize_t nRead; - do { - nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT); - } while (nRead == -1 && errno == EINTR); - - if (nRead < 0) { - int error = errno; -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); -#endif - if (error == EAGAIN || error == EWOULDBLOCK) { - return WOULD_BLOCK; - } - if (error == EPIPE || error == ENOTCONN) { - return DEAD_OBJECT; - } - return -error; - } - - if (nRead == 0) { // check for EOF -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); -#endif - return DEAD_OBJECT; - } - - if (!msg->isValid(nRead)) { -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received invalid message", mName.string()); -#endif - return BAD_VALUE; - } - -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); -#endif - return OK; -} - -sp<InputChannel> InputChannel::dup() const { - int fd = ::dup(getFd()); - return fd >= 0 ? new InputChannel(getName(), fd) : NULL; -} - - -// --- InputPublisher --- - -InputPublisher::InputPublisher(const sp<InputChannel>& channel) : - mChannel(channel) { -} - -InputPublisher::~InputPublisher() { -} - -status_t InputPublisher::publishKeyEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," - "downTime=%lld, eventTime=%lld", - mChannel->getName().string(), seq, - deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, - downTime, eventTime); -#endif - - if (!seq) { - ALOGE("Attempted to publish a key event with sequence number 0."); - return BAD_VALUE; - } - - InputMessage msg; - msg.header.type = InputMessage::TYPE_KEY; - msg.body.key.seq = seq; - msg.body.key.deviceId = deviceId; - msg.body.key.source = source; - msg.body.key.action = action; - msg.body.key.flags = flags; - msg.body.key.keyCode = keyCode; - msg.body.key.scanCode = scanCode; - msg.body.key.metaState = metaState; - msg.body.key.repeatCount = repeatCount; - msg.body.key.downTime = downTime; - msg.body.key.eventTime = eventTime; - return mChannel->sendMessage(&msg); -} - -status_t InputPublisher::publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " - "xOffset=%f, yOffset=%f, " - "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " - "pointerCount=%d", - mChannel->getName().string(), seq, - deviceId, source, action, flags, edgeFlags, metaState, buttonState, - xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); -#endif - - if (!seq) { - ALOGE("Attempted to publish a motion event with sequence number 0."); - return BAD_VALUE; - } - - if (pointerCount > MAX_POINTERS || pointerCount < 1) { - ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.", - mChannel->getName().string(), pointerCount); - return BAD_VALUE; - } - - InputMessage msg; - msg.header.type = InputMessage::TYPE_MOTION; - msg.body.motion.seq = seq; - msg.body.motion.deviceId = deviceId; - msg.body.motion.source = source; - msg.body.motion.action = action; - msg.body.motion.flags = flags; - msg.body.motion.edgeFlags = edgeFlags; - msg.body.motion.metaState = metaState; - msg.body.motion.buttonState = buttonState; - msg.body.motion.xOffset = xOffset; - msg.body.motion.yOffset = yOffset; - msg.body.motion.xPrecision = xPrecision; - msg.body.motion.yPrecision = yPrecision; - msg.body.motion.downTime = downTime; - msg.body.motion.eventTime = eventTime; - msg.body.motion.pointerCount = pointerCount; - for (size_t i = 0; i < pointerCount; i++) { - msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); - msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); - } - return mChannel->sendMessage(&msg); -} - -status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ receiveFinishedSignal", - mChannel->getName().string()); -#endif - - InputMessage msg; - status_t result = mChannel->receiveMessage(&msg); - if (result) { - *outSeq = 0; - *outHandled = false; - return result; - } - if (msg.header.type != InputMessage::TYPE_FINISHED) { - ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", - mChannel->getName().string(), msg.header.type); - return UNKNOWN_ERROR; - } - *outSeq = msg.body.finished.seq; - *outHandled = msg.body.finished.handled; - return OK; -} - -// --- InputConsumer --- - -InputConsumer::InputConsumer(const sp<InputChannel>& channel) : - mResampleTouch(isTouchResamplingEnabled()), - mChannel(channel), mMsgDeferred(false) { -} - -InputConsumer::~InputConsumer() { -} - -bool InputConsumer::isTouchResamplingEnabled() { - char value[PROPERTY_VALUE_MAX]; - int length = property_get("debug.inputconsumer.resample", value, NULL); - if (length > 0) { - if (!strcmp("0", value)) { - return false; - } - if (strcmp("1", value)) { - ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'. " - "Use '1' or '0'."); - } - } - return true; -} - -status_t InputConsumer::consume(InputEventFactoryInterface* factory, - bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", - mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime); -#endif - - *outSeq = 0; - *outEvent = NULL; - - // Fetch the next input message. - // Loop until an event can be returned or no additional events are received. - while (!*outEvent) { - if (mMsgDeferred) { - // mMsg contains a valid input message from the previous call to consume - // that has not yet been processed. - mMsgDeferred = false; - } else { - // Receive a fresh message. - status_t result = mChannel->receiveMessage(&mMsg); - if (result) { - // Consume the next batched event unless batches are being held for later. - if (consumeBatches || result != WOULD_BLOCK) { - result = consumeBatch(factory, frameTime, outSeq, outEvent); - if (*outEvent) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - } - return result; - } - } - - switch (mMsg.header.type) { - case InputMessage::TYPE_KEY: { - KeyEvent* keyEvent = factory->createKeyEvent(); - if (!keyEvent) return NO_MEMORY; - - initializeKeyEvent(keyEvent, &mMsg); - *outSeq = mMsg.body.key.seq; - *outEvent = keyEvent; -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source); - if (batchIndex >= 0) { - Batch& batch = mBatches.editItemAt(batchIndex); - if (canAddSample(batch, &mMsg)) { - batch.samples.push(mMsg); -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ appended to batch event", - mChannel->getName().string()); -#endif - break; - } else { - // We cannot append to the batch in progress, so we need to consume - // the previous batch right now and defer the new message until later. - mMsgDeferred = true; - status_t result = consumeSamples(factory, - batch, batch.samples.size(), outSeq, outEvent); - mBatches.removeAt(batchIndex); - if (result) { - return result; - } -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed batch event and " - "deferred current event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - } - - // Start a new batch if needed. - if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE - || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mBatches.push(); - Batch& batch = mBatches.editTop(); - batch.samples.push(mMsg); -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ started batch event", - mChannel->getName().string()); -#endif - break; - } - - MotionEvent* motionEvent = factory->createMotionEvent(); - if (! motionEvent) return NO_MEMORY; - - updateTouchState(&mMsg); - initializeMotionEvent(motionEvent, &mMsg); - *outSeq = mMsg.body.motion.seq; - *outEvent = motionEvent; -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - - default: - ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", - mChannel->getName().string(), mMsg.header.type); - return UNKNOWN_ERROR; - } - } - return OK; -} - -status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, - nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { - status_t result; - for (size_t i = mBatches.size(); i-- > 0; ) { - Batch& batch = mBatches.editItemAt(i); - if (frameTime < 0) { - result = consumeSamples(factory, batch, batch.samples.size(), - outSeq, outEvent); - mBatches.removeAt(i); - return result; - } - - nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY; - ssize_t split = findSampleNoLaterThan(batch, sampleTime); - if (split < 0) { - continue; - } - - result = consumeSamples(factory, batch, split + 1, outSeq, outEvent); - const InputMessage* next; - if (batch.samples.isEmpty()) { - mBatches.removeAt(i); - next = NULL; - } else { - next = &batch.samples.itemAt(0); - } - if (!result) { - resampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next); - } - return result; - } - - return WOULD_BLOCK; -} - -status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, - Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) { - MotionEvent* motionEvent = factory->createMotionEvent(); - if (! motionEvent) return NO_MEMORY; - - uint32_t chain = 0; - for (size_t i = 0; i < count; i++) { - InputMessage& msg = batch.samples.editItemAt(i); - updateTouchState(&msg); - if (i) { - SeqChain seqChain; - seqChain.seq = msg.body.motion.seq; - seqChain.chain = chain; - mSeqChains.push(seqChain); - addSample(motionEvent, &msg); - } else { - initializeMotionEvent(motionEvent, &msg); - } - chain = msg.body.motion.seq; - } - batch.samples.removeItemsAt(0, count); - - *outSeq = chain; - *outEvent = motionEvent; - return OK; -} - -void InputConsumer::updateTouchState(InputMessage* msg) { - if (!mResampleTouch || - !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - - int32_t deviceId = msg->body.motion.deviceId; - int32_t source = msg->body.motion.source; - nsecs_t eventTime = msg->body.motion.eventTime; - - // Update the touch state history to incorporate the new input message. - // If the message is in the past relative to the most recently produced resampled - // touch, then use the resampled time and coordinates instead. - switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findTouchState(deviceId, source); - if (index < 0) { - mTouchStates.push(); - index = mTouchStates.size() - 1; - } - TouchState& touchState = mTouchStates.editItemAt(index); - touchState.initialize(deviceId, source); - touchState.addHistory(msg); - break; - } - - case AMOTION_EVENT_ACTION_MOVE: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - TouchState& touchState = mTouchStates.editItemAt(index); - touchState.addHistory(msg); - if (eventTime < touchState.lastResample.eventTime) { - rewriteMessage(touchState, msg); - } else { - touchState.lastResample.idBits.clear(); - } - } - break; - } - - case AMOTION_EVENT_ACTION_POINTER_DOWN: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - TouchState& touchState = mTouchStates.editItemAt(index); - touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId()); - rewriteMessage(touchState, msg); - } - break; - } - - case AMOTION_EVENT_ACTION_POINTER_UP: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - TouchState& touchState = mTouchStates.editItemAt(index); - rewriteMessage(touchState, msg); - touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId()); - } - break; - } - - case AMOTION_EVENT_ACTION_SCROLL: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - const TouchState& touchState = mTouchStates.itemAt(index); - rewriteMessage(touchState, msg); - } - break; - } - - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - const TouchState& touchState = mTouchStates.itemAt(index); - rewriteMessage(touchState, msg); - mTouchStates.removeAt(index); - } - break; - } - } -} - -void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) { - for (size_t i = 0; i < msg->body.motion.pointerCount; i++) { - uint32_t id = msg->body.motion.pointers[i].properties.id; - if (state.lastResample.idBits.hasBit(id)) { - PointerCoords& msgCoords = msg->body.motion.pointers[i].coords; - const PointerCoords& resampleCoords = state.lastResample.getPointerById(id); -#if DEBUG_RESAMPLING - ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id, - resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X), - resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y), - msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X), - msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y)); -#endif - msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX()); - msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY()); - } - } -} - -void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, - const InputMessage* next) { - if (!mResampleTouch - || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER) - || event->getAction() != AMOTION_EVENT_ACTION_MOVE) { - return; - } - - ssize_t index = findTouchState(event->getDeviceId(), event->getSource()); - if (index < 0) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, no touch state for device."); -#endif - return; - } - - TouchState& touchState = mTouchStates.editItemAt(index); - if (touchState.historySize < 1) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, no history for device."); -#endif - return; - } - - // Ensure that the current sample has all of the pointers that need to be reported. - const History* current = touchState.getHistory(0); - size_t pointerCount = event->getPointerCount(); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t id = event->getPointerId(i); - if (!current->idBits.hasBit(id)) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, missing id %d", id); -#endif - return; - } - } - - // Find the data to use for resampling. - const History* other; - History future; - float alpha; - if (next) { - // Interpolate between current sample and future sample. - // So current->eventTime <= sampleTime <= future.eventTime. - future.initializeFrom(next); - other = &future; - nsecs_t delta = future.eventTime - current->eventTime; - if (delta < RESAMPLE_MIN_DELTA) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, delta time is %lld ns.", delta); -#endif - return; - } - alpha = float(sampleTime - current->eventTime) / delta; - } else if (touchState.historySize >= 2) { - // Extrapolate future sample using current sample and past sample. - // So other->eventTime <= current->eventTime <= sampleTime. - other = touchState.getHistory(1); - nsecs_t delta = current->eventTime - other->eventTime; - if (delta < RESAMPLE_MIN_DELTA) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, delta time is %lld ns.", delta); -#endif - return; - } - nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION); - if (sampleTime > maxPredict) { -#if DEBUG_RESAMPLING - ALOGD("Sample time is too far in the future, adjusting prediction " - "from %lld to %lld ns.", - sampleTime - current->eventTime, maxPredict - current->eventTime); -#endif - sampleTime = maxPredict; - } - alpha = float(current->eventTime - sampleTime) / delta; - } else { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, insufficient data."); -#endif - return; - } - - // Resample touch coordinates. - touchState.lastResample.eventTime = sampleTime; - touchState.lastResample.idBits.clear(); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t id = event->getPointerId(i); - touchState.lastResample.idToIndex[id] = i; - touchState.lastResample.idBits.markBit(id); - PointerCoords& resampledCoords = touchState.lastResample.pointers[i]; - const PointerCoords& currentCoords = current->getPointerById(id); - if (other->idBits.hasBit(id) - && shouldResampleTool(event->getToolType(i))) { - const PointerCoords& otherCoords = other->getPointerById(id); - resampledCoords.copyFrom(currentCoords); - resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, - lerp(currentCoords.getX(), otherCoords.getX(), alpha)); - resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, - lerp(currentCoords.getY(), otherCoords.getY(), alpha)); -#if DEBUG_RESAMPLING - ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), " - "other (%0.3f, %0.3f), alpha %0.3f", - id, resampledCoords.getX(), resampledCoords.getY(), - currentCoords.getX(), currentCoords.getY(), - otherCoords.getX(), otherCoords.getY(), - alpha); -#endif - } else { - resampledCoords.copyFrom(currentCoords); -#if DEBUG_RESAMPLING - ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", - id, resampledCoords.getX(), resampledCoords.getY(), - currentCoords.getX(), currentCoords.getY()); -#endif - } - } - - event->addSample(sampleTime, touchState.lastResample.pointers); -} - -bool InputConsumer::shouldResampleTool(int32_t toolType) { - return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", - mChannel->getName().string(), seq, handled ? "true" : "false"); -#endif - - if (!seq) { - ALOGE("Attempted to send a finished signal with sequence number 0."); - return BAD_VALUE; - } - - // Send finished signals for the batch sequence chain first. - size_t seqChainCount = mSeqChains.size(); - if (seqChainCount) { - uint32_t currentSeq = seq; - uint32_t chainSeqs[seqChainCount]; - size_t chainIndex = 0; - for (size_t i = seqChainCount; i-- > 0; ) { - const SeqChain& seqChain = mSeqChains.itemAt(i); - if (seqChain.seq == currentSeq) { - currentSeq = seqChain.chain; - chainSeqs[chainIndex++] = currentSeq; - mSeqChains.removeAt(i); - } - } - status_t status = OK; - while (!status && chainIndex-- > 0) { - status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled); - } - if (status) { - // An error occurred so at least one signal was not sent, reconstruct the chain. - do { - SeqChain seqChain; - seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq; - seqChain.chain = chainSeqs[chainIndex]; - mSeqChains.push(seqChain); - } while (chainIndex-- > 0); - return status; - } - } - - // Send finished signal for the last message in the batch. - return sendUnchainedFinishedSignal(seq, handled); -} - -status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) { - InputMessage msg; - msg.header.type = InputMessage::TYPE_FINISHED; - msg.body.finished.seq = seq; - msg.body.finished.handled = handled; - return mChannel->sendMessage(&msg); -} - -bool InputConsumer::hasDeferredEvent() const { - return mMsgDeferred; -} - -bool InputConsumer::hasPendingBatch() const { - return !mBatches.isEmpty(); -} - -ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const { - for (size_t i = 0; i < mBatches.size(); i++) { - const Batch& batch = mBatches.itemAt(i); - const InputMessage& head = batch.samples.itemAt(0); - if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) { - return i; - } - } - return -1; -} - -ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { - for (size_t i = 0; i < mTouchStates.size(); i++) { - const TouchState& touchState = mTouchStates.itemAt(i); - if (touchState.deviceId == deviceId && touchState.source == source) { - return i; - } - } - return -1; -} - -void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { - event->initialize( - msg->body.key.deviceId, - msg->body.key.source, - msg->body.key.action, - msg->body.key.flags, - msg->body.key.keyCode, - msg->body.key.scanCode, - msg->body.key.metaState, - msg->body.key.repeatCount, - msg->body.key.downTime, - msg->body.key.eventTime); -} - -void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { - size_t pointerCount = msg->body.motion.pointerCount; - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties); - pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); - } - - event->initialize( - msg->body.motion.deviceId, - msg->body.motion.source, - msg->body.motion.action, - msg->body.motion.flags, - msg->body.motion.edgeFlags, - msg->body.motion.metaState, - msg->body.motion.buttonState, - msg->body.motion.xOffset, - msg->body.motion.yOffset, - msg->body.motion.xPrecision, - msg->body.motion.yPrecision, - msg->body.motion.downTime, - msg->body.motion.eventTime, - pointerCount, - pointerProperties, - pointerCoords); -} - -void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { - size_t pointerCount = msg->body.motion.pointerCount; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); - } - - event->setMetaState(event->getMetaState() | msg->body.motion.metaState); - event->addSample(msg->body.motion.eventTime, pointerCoords); -} - -bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) { - const InputMessage& head = batch.samples.itemAt(0); - size_t pointerCount = msg->body.motion.pointerCount; - if (head.body.motion.pointerCount != pointerCount - || head.body.motion.action != msg->body.motion.action) { - return false; - } - for (size_t i = 0; i < pointerCount; i++) { - if (head.body.motion.pointers[i].properties - != msg->body.motion.pointers[i].properties) { - return false; - } - } - return true; -} - -ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) { - size_t numSamples = batch.samples.size(); - size_t index = 0; - while (index < numSamples - && batch.samples.itemAt(index).body.motion.eventTime <= time) { - index += 1; - } - return ssize_t(index) - 1; -} - -} // namespace android diff --git a/widget/gonk/libui/InputTransport.h b/widget/gonk/libui/InputTransport.h deleted file mode 100644 index 66ef2850a..000000000 --- a/widget/gonk/libui/InputTransport.h +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_INPUT_TRANSPORT_H -#define _ANDROIDFW_INPUT_TRANSPORT_H - -/** - * Native input transport. - * - * The InputChannel provides a mechanism for exchanging InputMessage structures across processes. - * - * The InputPublisher and InputConsumer each handle one end-point of an input channel. - * The InputPublisher is used by the input dispatcher to send events to the application. - * The InputConsumer is used by the application to receive events from the input dispatcher. - */ - -#include "Input.h" -#include <utils/Errors.h> -#include <utils/Timers.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/BitSet.h> - -namespace android { - -/* - * Intermediate representation used to send input events and related signals. - */ -struct InputMessage { - enum { - TYPE_KEY = 1, - TYPE_MOTION = 2, - TYPE_FINISHED = 3, - }; - - struct Header { - uint32_t type; - uint32_t padding; // 8 byte alignment for the body that follows - } header; - - union Body { - struct Key { - uint32_t seq; - nsecs_t eventTime; - int32_t deviceId; - int32_t source; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t repeatCount; - nsecs_t downTime; - - inline size_t size() const { - return sizeof(Key); - } - } key; - - struct Motion { - uint32_t seq; - nsecs_t eventTime; - int32_t deviceId; - int32_t source; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - nsecs_t downTime; - float xOffset; - float yOffset; - float xPrecision; - float yPrecision; - size_t pointerCount; - struct Pointer { - PointerProperties properties; - PointerCoords coords; - } pointers[MAX_POINTERS]; - - int32_t getActionId() const { - uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - return pointers[index].properties.id; - } - - inline size_t size() const { - return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS - + sizeof(Pointer) * pointerCount; - } - } motion; - - struct Finished { - uint32_t seq; - bool handled; - - inline size_t size() const { - return sizeof(Finished); - } - } finished; - } body; - - bool isValid(size_t actualSize) const; - size_t size() const; -}; - -/* - * An input channel consists of a local unix domain socket used to send and receive - * input messages across processes. Each channel has a descriptive name for debugging purposes. - * - * Each endpoint has its own InputChannel object that specifies its file descriptor. - * - * The input channel is closed when all references to it are released. - */ -class InputChannel : public RefBase { -protected: - virtual ~InputChannel(); - -public: - InputChannel(const String8& name, int fd); - - /* Creates a pair of input channels. - * - * Returns OK on success. - */ - static status_t openInputChannelPair(const String8& name, - sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel); - - inline String8 getName() const { return mName; } - inline int getFd() const { return mFd; } - - /* Sends a message to the other endpoint. - * - * If the channel is full then the message is guaranteed not to have been sent at all. - * Try again after the consumer has sent a finished signal indicating that it has - * consumed some of the pending messages from the channel. - * - * Returns OK on success. - * Returns WOULD_BLOCK if the channel is full. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t sendMessage(const InputMessage* msg); - - /* Receives a message sent by the other endpoint. - * - * If there is no message present, try again after poll() indicates that the fd - * is readable. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no message present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t receiveMessage(InputMessage* msg); - - /* Returns a new object that has a duplicate of this channel's fd. */ - sp<InputChannel> dup() const; - -private: - String8 mName; - int mFd; -}; - -/* - * Publishes input events to an input channel. - */ -class InputPublisher { -public: - /* Creates a publisher associated with an input channel. */ - explicit InputPublisher(const sp<InputChannel>& channel); - - /* Destroys the publisher and releases its input channel. */ - ~InputPublisher(); - - /* Gets the underlying input channel. */ - inline sp<InputChannel> getChannel() { return mChannel; } - - /* Publishes a key event to the input channel. - * - * Returns OK on success. - * Returns WOULD_BLOCK if the channel is full. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns BAD_VALUE if seq is 0. - * Other errors probably indicate that the channel is broken. - */ - status_t publishKeyEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime); - - /* Publishes a motion event to the input channel. - * - * Returns OK on success. - * Returns WOULD_BLOCK if the channel is full. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. - * Other errors probably indicate that the channel is broken. - */ - status_t publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); - - /* Receives the finished signal from the consumer in reply to the original dispatch signal. - * If a signal was received, returns the message sequence number, - * and whether the consumer handled the message. - * - * The returned sequence number is never 0 unless the operation failed. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no signal present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled); - -private: - sp<InputChannel> mChannel; -}; - -/* - * Consumes input events from an input channel. - */ -class InputConsumer { -public: - /* Creates a consumer associated with an input channel. */ - explicit InputConsumer(const sp<InputChannel>& channel); - - /* Destroys the consumer and releases its input channel. */ - ~InputConsumer(); - - /* Gets the underlying input channel. */ - inline sp<InputChannel> getChannel() { return mChannel; } - - /* Consumes an input event from the input channel and copies its contents into - * an InputEvent object created using the specified factory. - * - * Tries to combine a series of move events into larger batches whenever possible. - * - * If consumeBatches is false, then defers consuming pending batched events if it - * is possible for additional samples to be added to them later. Call hasPendingBatch() - * to determine whether a pending batch is available to be consumed. - * - * If consumeBatches is true, then events are still batched but they are consumed - * immediately as soon as the input channel is exhausted. - * - * The frameTime parameter specifies the time when the current display frame started - * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown. - * - * The returned sequence number is never 0 unless the operation failed. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no event present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns NO_MEMORY if the event could not be created. - * Other errors probably indicate that the channel is broken. - */ - status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, - nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); - - /* Sends a finished signal to the publisher to inform it that the message - * with the specified sequence number has finished being process and whether - * the message was handled by the consumer. - * - * Returns OK on success. - * Returns BAD_VALUE if seq is 0. - * Other errors probably indicate that the channel is broken. - */ - status_t sendFinishedSignal(uint32_t seq, bool handled); - - /* Returns true if there is a deferred event waiting. - * - * Should be called after calling consume() to determine whether the consumer - * has a deferred event to be processed. Deferred events are somewhat special in - * that they have already been removed from the input channel. If the input channel - * becomes empty, the client may need to do extra work to ensure that it processes - * the deferred event despite the fact that the input channel's file descriptor - * is not readable. - * - * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. - * This guarantees that all deferred events will be processed. - * - * Alternately, the caller can call hasDeferredEvent() to determine whether there is - * a deferred event waiting and then ensure that its event loop wakes up at least - * one more time to consume the deferred event. - */ - bool hasDeferredEvent() const; - - /* Returns true if there is a pending batch. - * - * Should be called after calling consume() with consumeBatches == false to determine - * whether consume() should be called again later on with consumeBatches == true. - */ - bool hasPendingBatch() const; - -private: - // True if touch resampling is enabled. - const bool mResampleTouch; - - // The input channel. - sp<InputChannel> mChannel; - - // The current input message. - InputMessage mMsg; - - // True if mMsg contains a valid input message that was deferred from the previous - // call to consume and that still needs to be handled. - bool mMsgDeferred; - - // Batched motion events per device and source. - struct Batch { - Vector<InputMessage> samples; - }; - Vector<Batch> mBatches; - - // Touch state per device and source, only for sources of class pointer. - struct History { - nsecs_t eventTime; - BitSet32 idBits; - int32_t idToIndex[MAX_POINTER_ID + 1]; - PointerCoords pointers[MAX_POINTERS]; - - void initializeFrom(const InputMessage* msg) { - eventTime = msg->body.motion.eventTime; - idBits.clear(); - for (size_t i = 0; i < msg->body.motion.pointerCount; i++) { - uint32_t id = msg->body.motion.pointers[i].properties.id; - idBits.markBit(id); - idToIndex[id] = i; - pointers[i].copyFrom(msg->body.motion.pointers[i].coords); - } - } - - const PointerCoords& getPointerById(uint32_t id) const { - return pointers[idToIndex[id]]; - } - }; - struct TouchState { - int32_t deviceId; - int32_t source; - size_t historyCurrent; - size_t historySize; - History history[2]; - History lastResample; - - void initialize(int32_t deviceId, int32_t source) { - this->deviceId = deviceId; - this->source = source; - historyCurrent = 0; - historySize = 0; - lastResample.eventTime = 0; - lastResample.idBits.clear(); - } - - void addHistory(const InputMessage* msg) { - historyCurrent ^= 1; - if (historySize < 2) { - historySize += 1; - } - history[historyCurrent].initializeFrom(msg); - } - - const History* getHistory(size_t index) const { - return &history[(historyCurrent + index) & 1]; - } - }; - Vector<TouchState> mTouchStates; - - // Chain of batched sequence numbers. When multiple input messages are combined into - // a batch, we append a record here that associates the last sequence number in the - // batch with the previous one. When the finished signal is sent, we traverse the - // chain to individually finish all input messages that were part of the batch. - struct SeqChain { - uint32_t seq; // sequence number of batched input message - uint32_t chain; // sequence number of previous batched input message - }; - Vector<SeqChain> mSeqChains; - - status_t consumeBatch(InputEventFactoryInterface* factory, - nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); - status_t consumeSamples(InputEventFactoryInterface* factory, - Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent); - - void updateTouchState(InputMessage* msg); - void rewriteMessage(const TouchState& state, InputMessage* msg); - void resampleTouchState(nsecs_t frameTime, MotionEvent* event, - const InputMessage *next); - - ssize_t findBatch(int32_t deviceId, int32_t source) const; - ssize_t findTouchState(int32_t deviceId, int32_t source) const; - - status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled); - - static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg); - static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg); - static void addSample(MotionEvent* event, const InputMessage* msg); - static bool canAddSample(const Batch& batch, const InputMessage* msg); - static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); - static bool shouldResampleTool(int32_t toolType); - - static bool isTouchResamplingEnabled(); -}; - -} // namespace android - -#endif // _ANDROIDFW_INPUT_TRANSPORT_H diff --git a/widget/gonk/libui/InputWindow.cpp b/widget/gonk/libui/InputWindow.cpp deleted file mode 100644 index 3aea445a0..000000000 --- a/widget/gonk/libui/InputWindow.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "InputWindow" - -#include "InputWindow.h" - -#include "cutils_log.h" - -namespace android { - -// --- InputWindowInfo --- - -bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { - return touchableRegion.contains(x, y); -} - -bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; -} - -bool InputWindowInfo::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; -} - -bool InputWindowInfo::supportsSplitTouch() const { - return layoutParamsFlags & FLAG_SPLIT_TOUCH; -} - - -// --- InputWindowHandle --- - -InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) : - inputApplicationHandle(inputApplicationHandle), mInfo(NULL) { -} - -InputWindowHandle::~InputWindowHandle() { - delete mInfo; -} - -void InputWindowHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = NULL; - } -} - -} // namespace android diff --git a/widget/gonk/libui/InputWindow.h b/widget/gonk/libui/InputWindow.h deleted file mode 100644 index cce5fd4fe..000000000 --- a/widget/gonk/libui/InputWindow.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H - -#include "Input.h" -#include "InputTransport.h" -#include <utils/RefBase.h> -#include <utils/Timers.h> -#include <utils/String8.h> - -#include <SkRegion.h> - -#include "InputApplication.h" - -namespace android { - -/* - * Describes the properties of a window that can receive input. - */ -struct InputWindowInfo { - // Window flags from WindowManager.LayoutParams - enum { - FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - FLAG_DIM_BEHIND = 0x00000002, - FLAG_BLUR_BEHIND = 0x00000004, - FLAG_NOT_FOCUSABLE = 0x00000008, - FLAG_NOT_TOUCHABLE = 0x00000010, - FLAG_NOT_TOUCH_MODAL = 0x00000020, - FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, - FLAG_KEEP_SCREEN_ON = 0x00000080, - FLAG_LAYOUT_IN_SCREEN = 0x00000100, - FLAG_LAYOUT_NO_LIMITS = 0x00000200, - FLAG_FULLSCREEN = 0x00000400, - FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, - FLAG_DITHER = 0x00001000, - FLAG_SECURE = 0x00002000, - FLAG_SCALED = 0x00004000, - FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, - FLAG_LAYOUT_INSET_DECOR = 0x00010000, - FLAG_ALT_FOCUSABLE_IM = 0x00020000, - FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, - FLAG_SHOW_WHEN_LOCKED = 0x00080000, - FLAG_SHOW_WALLPAPER = 0x00100000, - FLAG_TURN_SCREEN_ON = 0x00200000, - FLAG_DISMISS_KEYGUARD = 0x00400000, - FLAG_SPLIT_TOUCH = 0x00800000, - FLAG_HARDWARE_ACCELERATED = 0x01000000, - FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000, - FLAG_SLIPPERY = 0x04000000, - FLAG_NEEDS_MENU_KEY = 0x08000000, - FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, - FLAG_COMPATIBLE_WINDOW = 0x20000000, - FLAG_SYSTEM_ERROR = 0x40000000, - }; - - // Window types from WindowManager.LayoutParams - enum { - FIRST_APPLICATION_WINDOW = 1, - TYPE_BASE_APPLICATION = 1, - TYPE_APPLICATION = 2, - TYPE_APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, - TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, - TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, - TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, - TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, - TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, - TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, - TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, - TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, - TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, - TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, - TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, - TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, - TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, - TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, - TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, - TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, - TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, - TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, - TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, - TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, - TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, - TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, - TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, - TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, - TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, - LAST_SYSTEM_WINDOW = 2999, - }; - - enum { - INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, - INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, - }; - - sp<InputChannel> inputChannel; - String8 name; - int32_t layoutParamsFlags; - int32_t layoutParamsType; - nsecs_t dispatchingTimeout; - int32_t frameLeft; - int32_t frameTop; - int32_t frameRight; - int32_t frameBottom; - float scaleFactor; - SkRegion touchableRegion; - bool visible; - bool canReceiveKeys; - bool hasFocus; - bool hasWallpaper; - bool paused; - int32_t layer; - int32_t ownerPid; - int32_t ownerUid; - int32_t inputFeatures; - int32_t displayId; - - bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - bool frameContainsPoint(int32_t x, int32_t y) const; - - /* Returns true if the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool isTrustedOverlay() const; - - bool supportsSplitTouch() const; -}; - - -/* - * Handle for a window that can receive input. - * - * Used by the native input dispatcher to indirectly refer to the window manager objects - * that describe a window. - */ -class InputWindowHandle : public RefBase { -public: - const sp<InputApplicationHandle> inputApplicationHandle; - - inline const InputWindowInfo* getInfo() const { - return mInfo; - } - - inline sp<InputChannel> getInputChannel() const { - return mInfo ? mInfo->inputChannel : NULL; - } - - inline String8 getName() const { - return mInfo ? mInfo->name : String8("<invalid>"); - } - - inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - - /** - * Releases the storage used by the associated information when it is - * no longer needed. - */ - void releaseInfo(); - -protected: - InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle); - virtual ~InputWindowHandle(); - - InputWindowInfo* mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_WINDOW_H diff --git a/widget/gonk/libui/KeyCharacterMap.cpp b/widget/gonk/libui/KeyCharacterMap.cpp deleted file mode 100644 index cec0666ce..000000000 --- a/widget/gonk/libui/KeyCharacterMap.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "KeyCharacterMap" -#include "cutils_log.h" - -#include <stdlib.h> -#include <string.h> -#include "android_keycodes.h" -#include "Keyboard.h" -#include "KeyCharacterMap.h" - -#if HAVE_ANDROID_OS -#include <binder/Parcel.h> -#endif - -#include <utils/Errors.h> -#include "Tokenizer.h" -#include <utils/Timers.h> - -// Enables debug output for the parser. -#define DEBUG_PARSER 0 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - -// Enables debug output for mapping. -#define DEBUG_MAPPING 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; -static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; - -struct Modifier { - const char* label; - int32_t metaState; -}; -static const Modifier modifiers[] = { - { "shift", AMETA_SHIFT_ON }, - { "lshift", AMETA_SHIFT_LEFT_ON }, - { "rshift", AMETA_SHIFT_RIGHT_ON }, - { "alt", AMETA_ALT_ON }, - { "lalt", AMETA_ALT_LEFT_ON }, - { "ralt", AMETA_ALT_RIGHT_ON }, - { "ctrl", AMETA_CTRL_ON }, - { "lctrl", AMETA_CTRL_LEFT_ON }, - { "rctrl", AMETA_CTRL_RIGHT_ON }, - { "meta", AMETA_META_ON }, - { "lmeta", AMETA_META_LEFT_ON }, - { "rmeta", AMETA_META_RIGHT_ON }, - { "sym", AMETA_SYM_ON }, - { "fn", AMETA_FUNCTION_ON }, - { "capslock", AMETA_CAPS_LOCK_ON }, - { "numlock", AMETA_NUM_LOCK_ON }, - { "scrolllock", AMETA_SCROLL_LOCK_ON }, -}; - -#if DEBUG_MAPPING -static String8 toString(const char16_t* chars, size_t numChars) { - String8 result; - for (size_t i = 0; i < numChars; i++) { - result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); - } - return result; -} -#endif - - -// --- KeyCharacterMap --- - -sp<KeyCharacterMap> KeyCharacterMap::sEmpty = new KeyCharacterMap(); - -KeyCharacterMap::KeyCharacterMap() : - mType(KEYBOARD_TYPE_UNKNOWN) { -} - -KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : - RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode), - mKeysByUsageCode(other.mKeysByUsageCode) { - for (size_t i = 0; i < other.mKeys.size(); i++) { - mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i))); - } -} - -KeyCharacterMap::~KeyCharacterMap() { - for (size_t i = 0; i < mKeys.size(); i++) { - Key* key = mKeys.editValueAt(i); - delete key; - } -} - -status_t KeyCharacterMap::load(const String8& filename, - Format format, sp<KeyCharacterMap>* outMap) { - outMap->clear(); - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening key character map file %s.", status, filename.string()); - } else { - status = load(tokenizer, format, outMap); - delete tokenizer; - } - return status; -} - -status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents, - Format format, sp<KeyCharacterMap>* outMap) { - outMap->clear(); - - Tokenizer* tokenizer; - status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); - if (status) { - ALOGE("Error %d opening key character map.", status); - } else { - status = load(tokenizer, format, outMap); - delete tokenizer; - } - return status; -} - -status_t KeyCharacterMap::load(Tokenizer* tokenizer, - Format format, sp<KeyCharacterMap>* outMap) { - status_t status = OK; - sp<KeyCharacterMap> map = new KeyCharacterMap(); - if (!map.get()) { - ALOGE("Error allocating key character map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map.get(), tokenizer, format); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (!status) { - *outMap = map; - } - } - return status; -} - -sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base, - const sp<KeyCharacterMap>& overlay) { - if (overlay == NULL) { - return base; - } - if (base == NULL) { - return overlay; - } - - sp<KeyCharacterMap> map = new KeyCharacterMap(*base.get()); - for (size_t i = 0; i < overlay->mKeys.size(); i++) { - int32_t keyCode = overlay->mKeys.keyAt(i); - Key* key = overlay->mKeys.valueAt(i); - ssize_t oldIndex = map->mKeys.indexOfKey(keyCode); - if (oldIndex >= 0) { - delete map->mKeys.valueAt(oldIndex); - map->mKeys.editValueAt(oldIndex) = new Key(*key); - } else { - map->mKeys.add(keyCode, new Key(*key)); - } - } - - for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) { - map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i), - overlay->mKeysByScanCode.valueAt(i)); - } - - for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) { - map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i), - overlay->mKeysByUsageCode.valueAt(i)); - } - return map; -} - -sp<KeyCharacterMap> KeyCharacterMap::empty() { - return sEmpty; -} - -int32_t KeyCharacterMap::getKeyboardType() const { - return mType; -} - -char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { - char16_t result = 0; - const Key* key; - if (getKey(keyCode, &key)) { - result = key->label; - } -#if DEBUG_MAPPING - ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); -#endif - return result; -} - -char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { - char16_t result = 0; - const Key* key; - if (getKey(keyCode, &key)) { - result = key->number; - } -#if DEBUG_MAPPING - ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); -#endif - return result; -} - -char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { - char16_t result = 0; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { - result = behavior->character; - } -#if DEBUG_MAPPING - ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); -#endif - return result; -} - -bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, - FallbackAction* outFallbackAction) const { - outFallbackAction->keyCode = 0; - outFallbackAction->metaState = 0; - - bool result = false; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { - if (behavior->fallbackKeyCode) { - outFallbackAction->keyCode = behavior->fallbackKeyCode; - outFallbackAction->metaState = metaState & ~behavior->metaState; - result = true; - } - } -#if DEBUG_MAPPING - ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " - "fallback keyCode=%d, fallback metaState=0x%08x.", - keyCode, metaState, result ? "true" : "false", - outFallbackAction->keyCode, outFallbackAction->metaState); -#endif - return result; -} - -char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, - int32_t metaState) const { - char16_t result = 0; - const Key* key; - if (getKey(keyCode, &key)) { - // Try to find the most general behavior that maps to this character. - // For example, the base key behavior will usually be last in the list. - // However, if we find a perfect meta state match for one behavior then use that one. - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if (behavior->character) { - for (size_t i = 0; i < numChars; i++) { - if (behavior->character == chars[i]) { - result = behavior->character; - if ((behavior->metaState & metaState) == behavior->metaState) { - goto ExactMatch; - } - break; - } - } - } - } - ExactMatch: ; - } -#if DEBUG_MAPPING - ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", - keyCode, toString(chars, numChars).string(), metaState, result); -#endif - return result; -} - -bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, - Vector<KeyEvent>& outEvents) const { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - for (size_t i = 0; i < numChars; i++) { - int32_t keyCode, metaState; - char16_t ch = chars[i]; - if (!findKey(ch, &keyCode, &metaState)) { -#if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", - deviceId, toString(chars, numChars).string(), ch); -#endif - return false; - } - - int32_t currentMetaState = 0; - addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); - addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); - addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); - addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); - } -#if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", - deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); - for (size_t i = 0; i < outEvents.size(); i++) { - ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", - outEvents[i].getKeyCode(), outEvents[i].getMetaState(), - outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); - } -#endif - return true; -} - -status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { - if (usageCode) { - ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); - if (index >= 0) { -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", - scanCode, usageCode, *outKeyCode); -#endif - *outKeyCode = mKeysByUsageCode.valueAt(index); - return OK; - } - } - if (scanCode) { - ssize_t index = mKeysByScanCode.indexOfKey(scanCode); - if (index >= 0) { -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", - scanCode, usageCode, *outKeyCode); -#endif - *outKeyCode = mKeysByScanCode.valueAt(index); - return OK; - } - } - -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); -#endif - *outKeyCode = AKEYCODE_UNKNOWN; - return NAME_NOT_FOUND; -} - -bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { - ssize_t index = mKeys.indexOfKey(keyCode); - if (index >= 0) { - *outKey = mKeys.valueAt(index); - return true; - } - return false; -} - -bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const { - const Key* key; - if (getKey(keyCode, &key)) { - const Behavior* behavior = key->firstBehavior; - while (behavior) { - if (matchesMetaState(metaState, behavior->metaState)) { - *outKey = key; - *outBehavior = behavior; - return true; - } - behavior = behavior->next; - } - } - return false; -} - -bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { - // Behavior must have at least the set of meta states specified. - // And if the key event has CTRL, ALT or META then the behavior must exactly - // match those, taking into account that a behavior can specify that it handles - // one, both or either of a left/right modifier pair. - if ((eventMetaState & behaviorMetaState) == behaviorMetaState) { - const int32_t EXACT_META_STATES = - AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON - | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON - | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON; - int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES; - if (behaviorMetaState & AMETA_CTRL_ON) { - unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); - } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { - unmatchedMetaState &= ~AMETA_CTRL_ON; - } - if (behaviorMetaState & AMETA_ALT_ON) { - unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); - } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { - unmatchedMetaState &= ~AMETA_ALT_ON; - } - if (behaviorMetaState & AMETA_META_ON) { - unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); - } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { - unmatchedMetaState &= ~AMETA_META_ON; - } - return !unmatchedMetaState; - } - return false; -} - -bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { - if (!ch) { - return false; - } - - for (size_t i = 0; i < mKeys.size(); i++) { - const Key* key = mKeys.valueAt(i); - - // Try to find the most general behavior that maps to this character. - // For example, the base key behavior will usually be last in the list. - const Behavior* found = NULL; - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if (behavior->character == ch) { - found = behavior; - } - } - if (found) { - *outKeyCode = mKeys.keyAt(i); - *outMetaState = found->metaState; - return true; - } - } - return false; -} - -void KeyCharacterMap::addKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { - outEvents.push(); - KeyEvent& event = outEvents.editTop(); - event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - 0, keyCode, 0, metaState, 0, time, time); -} - -void KeyCharacterMap::addMetaKeys(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t* currentMetaState) { - // Add and remove meta keys symmetrically. - if (down) { - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); - - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, - AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, - AMETA_SHIFT_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, - AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, - AMETA_ALT_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, - AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, - AMETA_CTRL_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, - AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, - AMETA_META_ON, currentMetaState); - - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); - } else { - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); - - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, - AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, - AMETA_META_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, - AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, - AMETA_CTRL_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, - AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, - AMETA_ALT_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, - AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, - AMETA_SHIFT_ON, currentMetaState); - - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); - } -} - -bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState) { - if ((metaState & keyMetaState) == keyMetaState) { - *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); - addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); - return true; - } - return false; -} - -void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t leftKeyCode, int32_t leftKeyMetaState, - int32_t rightKeyCode, int32_t rightKeyMetaState, - int32_t eitherKeyMetaState, - int32_t* currentMetaState) { - bool specific = false; - specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, - leftKeyCode, leftKeyMetaState, currentMetaState); - specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, - rightKeyCode, rightKeyMetaState, currentMetaState); - - if (!specific) { - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, - leftKeyCode, eitherKeyMetaState, currentMetaState); - } -} - -void KeyCharacterMap::addLockedMetaKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState) { - if ((metaState & keyMetaState) == keyMetaState) { - *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); - addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); - *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); - addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); - } -} - -#if HAVE_ANDROID_OS -sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) { - sp<KeyCharacterMap> map = new KeyCharacterMap(); - map->mType = parcel->readInt32(); - size_t numKeys = parcel->readInt32(); - if (parcel->errorCheck()) { - return NULL; - } - - for (size_t i = 0; i < numKeys; i++) { - int32_t keyCode = parcel->readInt32(); - char16_t label = parcel->readInt32(); - char16_t number = parcel->readInt32(); - if (parcel->errorCheck()) { - return NULL; - } - - Key* key = new Key(); - key->label = label; - key->number = number; - map->mKeys.add(keyCode, key); - - Behavior* lastBehavior = NULL; - while (parcel->readInt32()) { - int32_t metaState = parcel->readInt32(); - char16_t character = parcel->readInt32(); - int32_t fallbackKeyCode = parcel->readInt32(); - if (parcel->errorCheck()) { - return NULL; - } - - Behavior* behavior = new Behavior(); - behavior->metaState = metaState; - behavior->character = character; - behavior->fallbackKeyCode = fallbackKeyCode; - if (lastBehavior) { - lastBehavior->next = behavior; - } else { - key->firstBehavior = behavior; - } - lastBehavior = behavior; - } - - if (parcel->errorCheck()) { - return NULL; - } - } - return map; -} - -void KeyCharacterMap::writeToParcel(Parcel* parcel) const { - parcel->writeInt32(mType); - - size_t numKeys = mKeys.size(); - parcel->writeInt32(numKeys); - for (size_t i = 0; i < numKeys; i++) { - int32_t keyCode = mKeys.keyAt(i); - const Key* key = mKeys.valueAt(i); - parcel->writeInt32(keyCode); - parcel->writeInt32(key->label); - parcel->writeInt32(key->number); - for (const Behavior* behavior = key->firstBehavior; behavior != NULL; - behavior = behavior->next) { - parcel->writeInt32(1); - parcel->writeInt32(behavior->metaState); - parcel->writeInt32(behavior->character); - parcel->writeInt32(behavior->fallbackKeyCode); - } - parcel->writeInt32(0); - } -} -#endif - - -// --- KeyCharacterMap::Key --- - -KeyCharacterMap::Key::Key() : - label(0), number(0), firstBehavior(NULL) { -} - -KeyCharacterMap::Key::Key(const Key& other) : - label(other.label), number(other.number), - firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) { -} - -KeyCharacterMap::Key::~Key() { - Behavior* behavior = firstBehavior; - while (behavior) { - Behavior* next = behavior->next; - delete behavior; - behavior = next; - } -} - - -// --- KeyCharacterMap::Behavior --- - -KeyCharacterMap::Behavior::Behavior() : - next(NULL), metaState(0), character(0), fallbackKeyCode(0) { -} - -KeyCharacterMap::Behavior::Behavior(const Behavior& other) : - next(other.next ? new Behavior(*other.next) : NULL), - metaState(other.metaState), character(other.character), - fallbackKeyCode(other.fallbackKeyCode) { -} - - -// --- KeyCharacterMap::Parser --- - -KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) : - mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) { -} - -KeyCharacterMap::Parser::~Parser() { -} - -status_t KeyCharacterMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - switch (mState) { - case STATE_TOP: { - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "type") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseType(); - if (status) return status; - } else if (keywordToken == "map") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseMap(); - if (status) return status; - } else if (keywordToken == "key") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseKey(); - if (status) return status; - } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); - return BAD_VALUE; - } - break; - } - - case STATE_KEY: { - status_t status = parseKeyProperty(); - if (status) return status; - break; - } - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - } - - mTokenizer->nextLine(); - } - - if (mState != STATE_TOP) { - ALOGE("%s: Unterminated key description at end of file.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { - ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - if (mFormat == FORMAT_BASE) { - if (mMap->mType == KEYBOARD_TYPE_OVERLAY) { - ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } else if (mFormat == FORMAT_OVERLAY) { - if (mMap->mType != KEYBOARD_TYPE_OVERLAY) { - ALOGE("%s: Overlay keyboard layout missing required keyboard " - "'type OVERLAY' declaration.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } - - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseType() { - if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { - ALOGE("%s: Duplicate keyboard 'type' declaration.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - KeyboardType type; - String8 typeToken = mTokenizer->nextToken(WHITESPACE); - if (typeToken == "NUMERIC") { - type = KEYBOARD_TYPE_NUMERIC; - } else if (typeToken == "PREDICTIVE") { - type = KEYBOARD_TYPE_PREDICTIVE; - } else if (typeToken == "ALPHA") { - type = KEYBOARD_TYPE_ALPHA; - } else if (typeToken == "FULL") { - type = KEYBOARD_TYPE_FULL; - } else if (typeToken == "SPECIAL_FUNCTION") { - type = KEYBOARD_TYPE_SPECIAL_FUNCTION; - } else if (typeToken == "OVERLAY") { - type = KEYBOARD_TYPE_OVERLAY; - } else { - ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), - typeToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed type: type=%d.", type); -#endif - mMap->mType = type; - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseMap() { - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "key") { - mTokenizer->skipDelimiters(WHITESPACE); - return parseMapKey(); - } - ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); - return BAD_VALUE; -} - -status_t KeyCharacterMap::Parser::parseMapKey() { - String8 codeToken = mTokenizer->nextToken(WHITESPACE); - bool mapUsage = false; - if (codeToken == "usage") { - mapUsage = true; - mTokenizer->skipDelimiters(WHITESPACE); - codeToken = mTokenizer->nextToken(WHITESPACE); - } - - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - KeyedVector<int32_t, int32_t>& map = - mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; - if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); - if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed map key %s: code=%d, keyCode=%d.", - mapUsage ? "usage" : "scan code", code, keyCode); -#endif - map.add(code, keyCode); - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseKey() { - String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); - if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - if (mMap->mKeys.indexOfKey(keyCode) >= 0) { - ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); - if (openBraceToken != "{") { - ALOGE("%s: Expected '{' after key code label, got '%s'.", - mTokenizer->getLocation().string(), openBraceToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); -#endif - mKeyCode = keyCode; - mMap->mKeys.add(keyCode, new Key()); - mState = STATE_KEY; - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseKeyProperty() { - Key* key = mMap->mKeys.valueFor(mKeyCode); - String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); - if (token == "}") { - mState = STATE_TOP; - return finishKey(key); - } - - Vector<Property> properties; - - // Parse all comma-delimited property names up to the first colon. - for (;;) { - if (token == "label") { - properties.add(Property(PROPERTY_LABEL)); - } else if (token == "number") { - properties.add(Property(PROPERTY_NUMBER)); - } else { - int32_t metaState; - status_t status = parseModifier(token, &metaState); - if (status) { - ALOGE("%s: Expected a property name or modifier, got '%s'.", - mTokenizer->getLocation().string(), token.string()); - return status; - } - properties.add(Property(PROPERTY_META, metaState)); - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol()) { - char ch = mTokenizer->nextChar(); - if (ch == ':') { - break; - } else if (ch == ',') { - mTokenizer->skipDelimiters(WHITESPACE); - token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); - continue; - } - } - - ALOGE("%s: Expected ',' or ':' after property name.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - // Parse behavior after the colon. - mTokenizer->skipDelimiters(WHITESPACE); - - Behavior behavior; - bool haveCharacter = false; - bool haveFallback = false; - - do { - char ch = mTokenizer->peekChar(); - if (ch == '\'') { - char16_t character; - status_t status = parseCharacterLiteral(&character); - if (status || !character) { - ALOGE("%s: Invalid character literal for key.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - if (haveCharacter) { - ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - behavior.character = character; - haveCharacter = true; - } else { - token = mTokenizer->nextToken(WHITESPACE); - if (token == "none") { - if (haveCharacter) { - ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - haveCharacter = true; - } else if (token == "fallback") { - mTokenizer->skipDelimiters(WHITESPACE); - token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(token.string()); - if (!keyCode) { - ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); - return BAD_VALUE; - } - if (haveFallback) { - ALOGE("%s: Cannot combine multiple fallback key codes.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - behavior.fallbackKeyCode = keyCode; - haveFallback = true; - } else { - ALOGE("%s: Expected a key behavior after ':'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } - - mTokenizer->skipDelimiters(WHITESPACE); - } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#'); - - // Add the behavior. - for (size_t i = 0; i < properties.size(); i++) { - const Property& property = properties.itemAt(i); - switch (property.property) { - case PROPERTY_LABEL: - if (key->label) { - ALOGE("%s: Duplicate label for key.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - key->label = behavior.character; -#if DEBUG_PARSER - ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); -#endif - break; - case PROPERTY_NUMBER: - if (key->number) { - ALOGE("%s: Duplicate number for key.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - key->number = behavior.character; -#if DEBUG_PARSER - ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); -#endif - break; - case PROPERTY_META: { - for (Behavior* b = key->firstBehavior; b; b = b->next) { - if (b->metaState == property.metaState) { - ALOGE("%s: Duplicate key behavior for modifier.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } - Behavior* newBehavior = new Behavior(behavior); - newBehavior->metaState = property.metaState; - newBehavior->next = key->firstBehavior; - key->firstBehavior = newBehavior; -#if DEBUG_PARSER - ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode, - newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode); -#endif - break; - } - } - } - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::finishKey(Key* key) { - // Fill in default number property. - if (!key->number) { - char16_t digit = 0; - char16_t symbol = 0; - for (Behavior* b = key->firstBehavior; b; b = b->next) { - char16_t ch = b->character; - if (ch) { - if (ch >= '0' && ch <= '9') { - digit = ch; - } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*' - || ch == '-' || ch == '+' || ch == ',' || ch == '.' - || ch == '\'' || ch == ':' || ch == ';' || ch == '/') { - symbol = ch; - } - } - } - key->number = digit ? digit : symbol; - } - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { - if (token == "base") { - *outMetaState = 0; - return NO_ERROR; - } - - int32_t combinedMeta = 0; - - const char* str = token.string(); - const char* start = str; - for (const char* cur = str; ; cur++) { - char ch = *cur; - if (ch == '+' || ch == '\0') { - size_t len = cur - start; - int32_t metaState = 0; - for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { - if (strlen(modifiers[i].label) == len - && strncmp(modifiers[i].label, start, len) == 0) { - metaState = modifiers[i].metaState; - break; - } - } - if (!metaState) { - return BAD_VALUE; - } - if (combinedMeta & metaState) { - ALOGE("%s: Duplicate modifier combination '%s'.", - mTokenizer->getLocation().string(), token.string()); - return BAD_VALUE; - } - - combinedMeta |= metaState; - start = cur + 1; - - if (ch == '\0') { - break; - } - } - } - *outMetaState = combinedMeta; - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { - char ch = mTokenizer->nextChar(); - if (ch != '\'') { - goto Error; - } - - ch = mTokenizer->nextChar(); - if (ch == '\\') { - // Escape sequence. - ch = mTokenizer->nextChar(); - if (ch == 'n') { - *outCharacter = '\n'; - } else if (ch == 't') { - *outCharacter = '\t'; - } else if (ch == '\\') { - *outCharacter = '\\'; - } else if (ch == '\'') { - *outCharacter = '\''; - } else if (ch == '"') { - *outCharacter = '"'; - } else if (ch == 'u') { - *outCharacter = 0; - for (int i = 0; i < 4; i++) { - ch = mTokenizer->nextChar(); - int digit; - if (ch >= '0' && ch <= '9') { - digit = ch - '0'; - } else if (ch >= 'A' && ch <= 'F') { - digit = ch - 'A' + 10; - } else if (ch >= 'a' && ch <= 'f') { - digit = ch - 'a' + 10; - } else { - goto Error; - } - *outCharacter = (*outCharacter << 4) | digit; - } - } else { - goto Error; - } - } else if (ch >= 32 && ch <= 126 && ch != '\'') { - // ASCII literal character. - *outCharacter = ch; - } else { - goto Error; - } - - ch = mTokenizer->nextChar(); - if (ch != '\'') { - goto Error; - } - - // Ensure that we consumed the entire token. - if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { - return NO_ERROR; - } - -Error: - ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); - return BAD_VALUE; -} - -} // namespace android diff --git a/widget/gonk/libui/KeyCharacterMap.h b/widget/gonk/libui/KeyCharacterMap.h deleted file mode 100644 index c7a684105..000000000 --- a/widget/gonk/libui/KeyCharacterMap.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H -#define _ANDROIDFW_KEY_CHARACTER_MAP_H - -#include <stdint.h> - -#if HAVE_ANDROID_OS -#include <binder/IBinder.h> -#endif - -#include "Input.h" -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include "Tokenizer.h" -#include <utils/String8.h> -#include <utils/Unicode.h> -#include <utils/RefBase.h> - -namespace android { - -/** - * Describes a mapping from Android key codes to characters. - * Also specifies other functions of the keyboard such as the keyboard type - * and key modifier semantics. - * - * This object is immutable after it has been loaded. - */ -class KeyCharacterMap : public RefBase { -public: - enum KeyboardType { - KEYBOARD_TYPE_UNKNOWN = 0, - KEYBOARD_TYPE_NUMERIC = 1, - KEYBOARD_TYPE_PREDICTIVE = 2, - KEYBOARD_TYPE_ALPHA = 3, - KEYBOARD_TYPE_FULL = 4, - KEYBOARD_TYPE_SPECIAL_FUNCTION = 5, - KEYBOARD_TYPE_OVERLAY = 6, - }; - - enum Format { - // Base keyboard layout, may contain device-specific options, such as "type" declaration. - FORMAT_BASE = 0, - // Overlay keyboard layout, more restrictive, may be published by applications, - // cannot override device-specific options. - FORMAT_OVERLAY = 1, - // Either base or overlay layout ok. - FORMAT_ANY = 2, - }; - - // Substitute key code and meta state for fallback action. - struct FallbackAction { - int32_t keyCode; - int32_t metaState; - }; - - /* Loads a key character map from a file. */ - static status_t load(const String8& filename, Format format, sp<KeyCharacterMap>* outMap); - - /* Loads a key character map from its string contents. */ - static status_t loadContents(const String8& filename, - const char* contents, Format format, sp<KeyCharacterMap>* outMap); - - /* Combines a base key character map and an overlay. */ - static sp<KeyCharacterMap> combine(const sp<KeyCharacterMap>& base, - const sp<KeyCharacterMap>& overlay); - - /* Returns an empty key character map. */ - static sp<KeyCharacterMap> empty(); - - /* Gets the keyboard type. */ - int32_t getKeyboardType() const; - - /* Gets the primary character for this key as in the label physically printed on it. - * Returns 0 if none (eg. for non-printing keys). */ - char16_t getDisplayLabel(int32_t keyCode) const; - - /* Gets the Unicode character for the number or symbol generated by the key - * when the keyboard is used as a dialing pad. - * Returns 0 if no number or symbol is generated. - */ - char16_t getNumber(int32_t keyCode) const; - - /* Gets the Unicode character generated by the key and meta key modifiers. - * Returns 0 if no character is generated. - */ - char16_t getCharacter(int32_t keyCode, int32_t metaState) const; - - /* Gets the fallback action to use by default if the application does not - * handle the specified key. - * Returns true if an action was available, false if none. - */ - bool getFallbackAction(int32_t keyCode, int32_t metaState, - FallbackAction* outFallbackAction) const; - - /* Gets the first matching Unicode character that can be generated by the key, - * preferring the one with the specified meta key modifiers. - * Returns 0 if no matching character is generated. - */ - char16_t getMatch(int32_t keyCode, const char16_t* chars, - size_t numChars, int32_t metaState) const; - - /* Gets a sequence of key events that could plausibly generate the specified - * character sequence. Returns false if some of the characters cannot be generated. - */ - bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, - Vector<KeyEvent>& outEvents) const; - - /* Maps a scan code and usage code to a key code, in case this key map overrides - * the mapping in some way. */ - status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const; - -#if HAVE_ANDROID_OS - /* Reads a key map from a parcel. */ - static sp<KeyCharacterMap> readFromParcel(Parcel* parcel); - - /* Writes a key map to a parcel. */ - void writeToParcel(Parcel* parcel) const; -#endif - -protected: - virtual ~KeyCharacterMap(); - -private: - struct Behavior { - Behavior(); - Behavior(const Behavior& other); - - /* The next behavior in the list, or NULL if none. */ - Behavior* next; - - /* The meta key modifiers for this behavior. */ - int32_t metaState; - - /* The character to insert. */ - char16_t character; - - /* The fallback keycode if the key is not handled. */ - int32_t fallbackKeyCode; - }; - - struct Key { - Key(); - Key(const Key& other); - ~Key(); - - /* The single character label printed on the key, or 0 if none. */ - char16_t label; - - /* The number or symbol character generated by the key, or 0 if none. */ - char16_t number; - - /* The list of key behaviors sorted from most specific to least specific - * meta key binding. */ - Behavior* firstBehavior; - }; - - class Parser { - enum State { - STATE_TOP = 0, - STATE_KEY = 1, - }; - - enum { - PROPERTY_LABEL = 1, - PROPERTY_NUMBER = 2, - PROPERTY_META = 3, - }; - - struct Property { - inline Property(int32_t property = 0, int32_t metaState = 0) : - property(property), metaState(metaState) { } - - int32_t property; - int32_t metaState; - }; - - KeyCharacterMap* mMap; - Tokenizer* mTokenizer; - Format mFormat; - State mState; - int32_t mKeyCode; - - public: - Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format); - ~Parser(); - status_t parse(); - - private: - status_t parseType(); - status_t parseMap(); - status_t parseMapKey(); - status_t parseKey(); - status_t parseKeyProperty(); - status_t finishKey(Key* key); - status_t parseModifier(const String8& token, int32_t* outMetaState); - status_t parseCharacterLiteral(char16_t* outCharacter); - }; - - static sp<KeyCharacterMap> sEmpty; - - KeyedVector<int32_t, Key*> mKeys; - int mType; - - KeyedVector<int32_t, int32_t> mKeysByScanCode; - KeyedVector<int32_t, int32_t> mKeysByUsageCode; - - KeyCharacterMap(); - KeyCharacterMap(const KeyCharacterMap& other); - - bool getKey(int32_t keyCode, const Key** outKey) const; - bool getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const; - static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState); - - bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; - - static status_t load(Tokenizer* tokenizer, Format format, sp<KeyCharacterMap>* outMap); - - static void addKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); - static void addMetaKeys(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t* currentMetaState); - static bool addSingleEphemeralMetaKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState); - static void addDoubleEphemeralMetaKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t leftKeyCode, int32_t leftKeyMetaState, - int32_t rightKeyCode, int32_t rightKeyMetaState, - int32_t eitherKeyMetaState, - int32_t* currentMetaState); - static void addLockedMetaKey(Vector<KeyEvent>& outEvents, - int32_t deviceId, int32_t metaState, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState); -}; - -} // namespace android - -#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H diff --git a/widget/gonk/libui/KeyLayoutMap.cpp b/widget/gonk/libui/KeyLayoutMap.cpp deleted file mode 100644 index 8af4b84e0..000000000 --- a/widget/gonk/libui/KeyLayoutMap.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "KeyLayoutMap" -#include "cutils_log.h" - -#include <stdlib.h> -#include "android_keycodes.h" -#include "Keyboard.h" -#include "KeyLayoutMap.h" -#include <utils/Errors.h> -#include "Tokenizer.h" -#include <utils/Timers.h> - -// Enables debug output for the parser. -#define DEBUG_PARSER 0 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - -// Enables debug output for mapping. -#define DEBUG_MAPPING 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; - -// --- KeyLayoutMap --- - -KeyLayoutMap::KeyLayoutMap() { -} - -KeyLayoutMap::~KeyLayoutMap() { -} - -status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) { - outMap->clear(); - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening key layout map file %s.", status, filename.string()); - } else { - sp<KeyLayoutMap> map = new KeyLayoutMap(); - if (!map.get()) { - ALOGE("Error allocating key layout map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map.get(), tokenizer); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (!status) { - *outMap = map; - } - } - delete tokenizer; - } - return status; -} - -status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, - int32_t* outKeyCode, uint32_t* outFlags) const { - const Key* key = getKey(scanCode, usageCode); - if (!key) { -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); -#endif - *outKeyCode = AKEYCODE_UNKNOWN; - *outFlags = 0; - return NAME_NOT_FOUND; - } - - *outKeyCode = key->keyCode; - *outFlags = key->flags; - -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.", - scanCode, usageCode, *outKeyCode, *outFlags); -#endif - return NO_ERROR; -} - -const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const { - if (usageCode) { - ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); - if (index >= 0) { - return &mKeysByUsageCode.valueAt(index); - } - } - if (scanCode) { - ssize_t index = mKeysByScanCode.indexOfKey(scanCode); - if (index >= 0) { - return &mKeysByScanCode.valueAt(index); - } - } - return NULL; -} - -status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const { - const size_t N = mKeysByScanCode.size(); - for (size_t i=0; i<N; i++) { - if (mKeysByScanCode.valueAt(i).keyCode == keyCode) { - outScanCodes->add(mKeysByScanCode.keyAt(i)); - } - } - return NO_ERROR; -} - -status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { - ssize_t index = mAxes.indexOfKey(scanCode); - if (index < 0) { -#if DEBUG_MAPPING - ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); -#endif - return NAME_NOT_FOUND; - } - - *outAxisInfo = mAxes.valueAt(index); - -#if DEBUG_MAPPING - ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " - "splitValue=%d, flatOverride=%d.", - scanCode, - outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, - outAxisInfo->splitValue, outAxisInfo->flatOverride); -#endif - return NO_ERROR; -} - -status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const { - const size_t N = mLedsByScanCode.size(); - for (size_t i = 0; i < N; i++) { - if (mLedsByScanCode.valueAt(i).ledCode == ledCode) { - *outScanCode = mLedsByScanCode.keyAt(i); -#if DEBUG_MAPPING - ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode); -#endif - return NO_ERROR; - } - } -#if DEBUG_MAPPING - ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode); -#endif - return NAME_NOT_FOUND; -} - -status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const { - const size_t N = mLedsByUsageCode.size(); - for (size_t i = 0; i < N; i++) { - if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) { - *outUsageCode = mLedsByUsageCode.keyAt(i); -#if DEBUG_MAPPING - ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode); -#endif - return NO_ERROR; - } - } -#if DEBUG_MAPPING - ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode); -#endif - return NAME_NOT_FOUND; -} - - -// --- KeyLayoutMap::Parser --- - -KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : - mMap(map), mTokenizer(tokenizer) { -} - -KeyLayoutMap::Parser::~Parser() { -} - -status_t KeyLayoutMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "key") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseKey(); - if (status) return status; - } else if (keywordToken == "axis") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseAxis(); - if (status) return status; - } else if (keywordToken == "led") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseLed(); - if (status) return status; - } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - } - - mTokenizer->nextLine(); - } - return NO_ERROR; -} - -status_t KeyLayoutMap::Parser::parseKey() { - String8 codeToken = mTokenizer->nextToken(WHITESPACE); - bool mapUsage = false; - if (codeToken == "usage") { - mapUsage = true; - mTokenizer->skipDelimiters(WHITESPACE); - codeToken = mTokenizer->nextToken(WHITESPACE); - } - - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - KeyedVector<int32_t, Key>& map = - mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; - if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); - if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - - uint32_t flags = 0; - for (;;) { - mTokenizer->skipDelimiters(WHITESPACE); - if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; - - String8 flagToken = mTokenizer->nextToken(WHITESPACE); - uint32_t flag = getKeyFlagByLabel(flagToken.string()); - if (!flag) { - ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); - return BAD_VALUE; - } - if (flags & flag) { - ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); - return BAD_VALUE; - } - flags |= flag; - } - -#if DEBUG_PARSER - ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", - mapUsage ? "usage" : "scan code", code, keyCode, flags); -#endif - Key key; - key.keyCode = keyCode; - key.flags = flags; - map.add(code, key); - return NO_ERROR; -} - -status_t KeyLayoutMap::Parser::parseAxis() { - String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); - char* end; - int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); - return BAD_VALUE; - } - if (mMap->mAxes.indexOfKey(scanCode) >= 0) { - ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); - return BAD_VALUE; - } - - AxisInfo axisInfo; - - mTokenizer->skipDelimiters(WHITESPACE); - String8 token = mTokenizer->nextToken(WHITESPACE); - if (token == "invert") { - axisInfo.mode = AxisInfo::MODE_INVERT; - - mTokenizer->skipDelimiters(WHITESPACE); - String8 axisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = getAxisByLabel(axisToken.string()); - if (axisInfo.axis < 0) { - ALOGE("%s: Expected inverted axis label, got '%s'.", - mTokenizer->getLocation().string(), axisToken.string()); - return BAD_VALUE; - } - } else if (token == "split") { - axisInfo.mode = AxisInfo::MODE_SPLIT; - - mTokenizer->skipDelimiters(WHITESPACE); - String8 splitToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected split value, got '%s'.", - mTokenizer->getLocation().string(), splitToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = getAxisByLabel(lowAxisToken.string()); - if (axisInfo.axis < 0) { - ALOGE("%s: Expected low axis label, got '%s'.", - mTokenizer->getLocation().string(), lowAxisToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); - if (axisInfo.highAxis < 0) { - ALOGE("%s: Expected high axis label, got '%s'.", - mTokenizer->getLocation().string(), highAxisToken.string()); - return BAD_VALUE; - } - } else { - axisInfo.axis = getAxisByLabel(token.string()); - if (axisInfo.axis < 0) { - ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", - mTokenizer->getLocation().string(), token.string()); - return BAD_VALUE; - } - } - - for (;;) { - mTokenizer->skipDelimiters(WHITESPACE); - if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') { - break; - } - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "flat") { - mTokenizer->skipDelimiters(WHITESPACE); - String8 flatToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected flat value, got '%s'.", - mTokenizer->getLocation().string(), flatToken.string()); - return BAD_VALUE; - } - } else { - ALOGE("%s: Expected keyword 'flat', got '%s'.", - mTokenizer->getLocation().string(), keywordToken.string()); - return BAD_VALUE; - } - } - -#if DEBUG_PARSER - ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " - "splitValue=%d, flatOverride=%d.", - scanCode, - axisInfo.mode, axisInfo.axis, axisInfo.highAxis, - axisInfo.splitValue, axisInfo.flatOverride); -#endif - mMap->mAxes.add(scanCode, axisInfo); - return NO_ERROR; -} - -status_t KeyLayoutMap::Parser::parseLed() { - String8 codeToken = mTokenizer->nextToken(WHITESPACE); - bool mapUsage = false; - if (codeToken == "usage") { - mapUsage = true; - mTokenizer->skipDelimiters(WHITESPACE); - codeToken = mTokenizer->nextToken(WHITESPACE); - } - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - KeyedVector<int32_t, Led>& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; - if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t ledCode = getLedByLabel(ledCodeToken.string()); - if (ledCode < 0) { - ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), - ledCodeToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed led %s: code=%d, ledCode=%d.", - mapUsage ? "usage" : "scan code", code, ledCode); -#endif - - Led led; - led.ledCode = ledCode; - map.add(code, led); - return NO_ERROR; -} -}; diff --git a/widget/gonk/libui/KeyLayoutMap.h b/widget/gonk/libui/KeyLayoutMap.h deleted file mode 100644 index 8a6113447..000000000 --- a/widget/gonk/libui/KeyLayoutMap.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H -#define _ANDROIDFW_KEY_LAYOUT_MAP_H - -#include <stdint.h> -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include "Tokenizer.h" -#include <utils/RefBase.h> - -namespace android { - -struct AxisInfo { - enum Mode { - // Axis value is reported directly. - MODE_NORMAL = 0, - // Axis value should be inverted before reporting. - MODE_INVERT = 1, - // Axis value should be split into two axes - MODE_SPLIT = 2, - }; - - // Axis mode. - Mode mode; - - // Axis id. - // When split, this is the axis used for values smaller than the split position. - int32_t axis; - - // When split, this is the axis used for values after higher than the split position. - int32_t highAxis; - - // The split value, or 0 if not split. - int32_t splitValue; - - // The flat value, or -1 if none. - int32_t flatOverride; - - AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) { - } -}; - -/** - * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. - * - * This object is immutable after it has been loaded. - */ -class KeyLayoutMap : public RefBase { -public: - static status_t load(const String8& filename, sp<KeyLayoutMap>* outMap); - - status_t mapKey(int32_t scanCode, int32_t usageCode, - int32_t* outKeyCode, uint32_t* outFlags) const; - status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const; - status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const; - status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const; - - status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const; - -protected: - virtual ~KeyLayoutMap(); - -private: - struct Key { - int32_t keyCode; - uint32_t flags; - }; - - struct Led { - int32_t ledCode; - }; - - - KeyedVector<int32_t, Key> mKeysByScanCode; - KeyedVector<int32_t, Key> mKeysByUsageCode; - KeyedVector<int32_t, AxisInfo> mAxes; - KeyedVector<int32_t, Led> mLedsByScanCode; - KeyedVector<int32_t, Led> mLedsByUsageCode; - - KeyLayoutMap(); - - const Key* getKey(int32_t scanCode, int32_t usageCode) const; - - class Parser { - KeyLayoutMap* mMap; - Tokenizer* mTokenizer; - - public: - Parser(KeyLayoutMap* map, Tokenizer* tokenizer); - ~Parser(); - status_t parse(); - - private: - status_t parseKey(); - status_t parseAxis(); - status_t parseLed(); - }; -}; - -} // namespace android - -#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H diff --git a/widget/gonk/libui/Keyboard.cpp b/widget/gonk/libui/Keyboard.cpp deleted file mode 100644 index 62bb53b7b..000000000 --- a/widget/gonk/libui/Keyboard.cpp +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Keyboard" -#include "cutils_log.h" - -#include <stdlib.h> -#include <unistd.h> -#include <limits.h> - -#include "Keyboard.h" -#include "KeycodeLabels.h" -#include "KeyLayoutMap.h" -#include "KeyCharacterMap.h" -#include "InputDevice.h" -#include <utils/Errors.h> -#include <cutils/properties.h> - -namespace android { - -// --- KeyMap --- - -KeyMap::KeyMap() { -} - -KeyMap::~KeyMap() { -} - -status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, - const PropertyMap* deviceConfiguration) { - // Use the configured key layout if available. - if (deviceConfiguration) { - String8 keyLayoutName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), - keyLayoutName)) { - status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); - if (status == NAME_NOT_FOUND) { - ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " - "it was not found.", - deviceIdenfifier.name.string(), keyLayoutName.string()); - } - } - - String8 keyCharacterMapName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), - keyCharacterMapName)) { - status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); - if (status == NAME_NOT_FOUND) { - ALOGE("Configuration for keyboard device '%s' requested keyboard character " - "map '%s' but it was not found.", - deviceIdenfifier.name.string(), keyLayoutName.string()); - } - } - - if (isComplete()) { - return OK; - } - } - - // Try searching by device identifier. - if (probeKeyMap(deviceIdenfifier, String8::empty())) { - return OK; - } - - // Fall back on the Generic key map. - // TODO Apply some additional heuristics here to figure out what kind of - // generic key map to use (US English, etc.) for typical external keyboards. - if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { - return OK; - } - - // Try the Virtual key map as a last resort. - if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { - return OK; - } - - // Give up! - ALOGE("Could not determine key map for device '%s' and no default key maps were found!", - deviceIdenfifier.name.string()); - return NAME_NOT_FOUND; -} - -bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, - const String8& keyMapName) { - if (!haveKeyLayout()) { - loadKeyLayout(deviceIdentifier, keyMapName); - } - if (!haveKeyCharacterMap()) { - loadKeyCharacterMap(deviceIdentifier, keyMapName); - } - return isComplete(); -} - -status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, - const String8& name) { - String8 path(getPath(deviceIdentifier, name, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); - if (path.isEmpty()) { - return NAME_NOT_FOUND; - } - - status_t status = KeyLayoutMap::load(path, &keyLayoutMap); - if (status) { - return status; - } - - keyLayoutFile.setTo(path); - return OK; -} - -status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, - const String8& name) { - String8 path(getPath(deviceIdentifier, name, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); - if (path.isEmpty()) { - return NAME_NOT_FOUND; - } - - status_t status = KeyCharacterMap::load(path, - KeyCharacterMap::FORMAT_BASE, &keyCharacterMap); - if (status) { - return status; - } - - keyCharacterMapFile.setTo(path); - return OK; -} - -String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, - const String8& name, InputDeviceConfigurationFileType type) { - return name.isEmpty() - ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) - : getInputDeviceConfigurationFilePathByName(name, type); -} - - -// --- Global functions --- - -bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, - const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { - if (!keyMap->haveKeyCharacterMap() - || keyMap->keyCharacterMap->getKeyboardType() - == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { - return false; - } - - if (deviceConfiguration) { - bool builtIn = false; - if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) - && builtIn) { - return true; - } - } - - return strstr(deviceIdentifier.name.string(), "-keypad"); -} - -static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) { - while (list->literal) { - if (strcmp(literal, list->literal) == 0) { - return list->value; - } - list++; - } - return list->value; -} - -static const char* lookupLabelByValue(int value, const KeycodeLabel *list) { - while (list->literal) { - if (list->value == value) { - return list->literal; - } - list++; - } - return NULL; -} - -int32_t getKeyCodeByLabel(const char* label) { - return int32_t(lookupValueByLabel(label, KEYCODES)); -} - -uint32_t getKeyFlagByLabel(const char* label) { - return uint32_t(lookupValueByLabel(label, FLAGS)); -} - -int32_t getAxisByLabel(const char* label) { - return int32_t(lookupValueByLabel(label, AXES)); -} - -const char* getAxisLabel(int32_t axisId) { - return lookupLabelByValue(axisId, AXES); -} - -int32_t getLedByLabel(const char* label) { - return int32_t(lookupValueByLabel(label, LEDS)); -} -static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { - int32_t newMetaState; - if (down) { - newMetaState = oldMetaState | mask; - } else { - newMetaState = oldMetaState & - ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON); - } - - if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { - newMetaState |= AMETA_ALT_ON; - } - - if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { - newMetaState |= AMETA_SHIFT_ON; - } - - if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { - newMetaState |= AMETA_CTRL_ON; - } - - if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { - newMetaState |= AMETA_META_ON; - } - return newMetaState; -} - -static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) { - if (down) { - return oldMetaState; - } else { - return oldMetaState ^ mask; - } -} - -int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { - switch (keyCode) { - case AKEYCODE_ALT_LEFT: - return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState); - case AKEYCODE_ALT_RIGHT: - return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState); - case AKEYCODE_SHIFT_LEFT: - return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState); - case AKEYCODE_SHIFT_RIGHT: - return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState); - case AKEYCODE_SYM: - return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState); - case AKEYCODE_FUNCTION: - return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState); - case AKEYCODE_CTRL_LEFT: - return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState); - case AKEYCODE_CTRL_RIGHT: - return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState); - case AKEYCODE_META_LEFT: - return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState); - case AKEYCODE_META_RIGHT: - return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState); - case AKEYCODE_CAPS_LOCK: - return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState); - case AKEYCODE_NUM_LOCK: - return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState); - case AKEYCODE_SCROLL_LOCK: - return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState); - default: - return oldMetaState; - } -} - -bool isMetaKey(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_ALT_LEFT: - case AKEYCODE_ALT_RIGHT: - case AKEYCODE_SHIFT_LEFT: - case AKEYCODE_SHIFT_RIGHT: - case AKEYCODE_SYM: - case AKEYCODE_FUNCTION: - case AKEYCODE_CTRL_LEFT: - case AKEYCODE_CTRL_RIGHT: - case AKEYCODE_META_LEFT: - case AKEYCODE_META_RIGHT: - case AKEYCODE_CAPS_LOCK: - case AKEYCODE_NUM_LOCK: - case AKEYCODE_SCROLL_LOCK: - return true; - default: - return false; - } -} - - -} // namespace android diff --git a/widget/gonk/libui/Keyboard.h b/widget/gonk/libui/Keyboard.h deleted file mode 100644 index 65921b25b..000000000 --- a/widget/gonk/libui/Keyboard.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_KEYBOARD_H -#define _ANDROIDFW_KEYBOARD_H - -#include "Input.h" -#include "InputDevice.h" -#include <utils/Errors.h> -#include <utils/String8.h> -#include <utils/PropertyMap.h> - -namespace android { - -enum { - /* Device id of the built in keyboard. */ - DEVICE_ID_BUILT_IN_KEYBOARD = 0, - - /* Device id of a generic virtual keyboard with a full layout that can be used - * to synthesize key events. */ - DEVICE_ID_VIRTUAL_KEYBOARD = -1, -}; - -class KeyLayoutMap; -class KeyCharacterMap; - -/** - * Loads the key layout map and key character map for a keyboard device. - */ -class KeyMap { -public: - String8 keyLayoutFile; - sp<KeyLayoutMap> keyLayoutMap; - - String8 keyCharacterMapFile; - sp<KeyCharacterMap> keyCharacterMap; - - KeyMap(); - ~KeyMap(); - - status_t load(const InputDeviceIdentifier& deviceIdenfier, - const PropertyMap* deviceConfiguration); - - inline bool haveKeyLayout() const { - return !keyLayoutFile.isEmpty(); - } - - inline bool haveKeyCharacterMap() const { - return !keyCharacterMapFile.isEmpty(); - } - - inline bool isComplete() const { - return haveKeyLayout() && haveKeyCharacterMap(); - } - -private: - bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); - status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name); - status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, - const String8& name); - String8 getPath(const InputDeviceIdentifier& deviceIdentifier, - const String8& name, InputDeviceConfigurationFileType type); -}; - -/** - * Returns true if the keyboard is eligible for use as a built-in keyboard. - */ -extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, - const PropertyMap* deviceConfiguration, const KeyMap* keyMap); - -/** - * Gets a key code by its short form label, eg. "HOME". - * Returns 0 if unknown. - */ -extern int32_t getKeyCodeByLabel(const char* label); - -/** - * Gets a key flag by its short form label, eg. "WAKE". - * Returns 0 if unknown. - */ -extern uint32_t getKeyFlagByLabel(const char* label); - -/** - * Gets a axis by its short form label, eg. "X". - * Returns -1 if unknown. - */ -extern int32_t getAxisByLabel(const char* label); - -/** - * Gets a axis label by its id. - * Returns NULL if unknown. - */ -extern const char* getAxisLabel(int32_t axisId); - -extern int32_t getLedByLabel(const char* label); - -/** - * Updates a meta state field when a key is pressed or released. - */ -extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); - -/** - * Returns true if a key is a meta key like ALT or CAPS_LOCK. - */ -extern bool isMetaKey(int32_t keyCode); - -} // namespace android - -#endif // _ANDROIDFW_KEYBOARD_H diff --git a/widget/gonk/libui/KeycodeLabels.h b/widget/gonk/libui/KeycodeLabels.h deleted file mode 100644 index 9f994597b..000000000 --- a/widget/gonk/libui/KeycodeLabels.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_KEYCODE_LABELS_H -#define _ANDROIDFW_KEYCODE_LABELS_H - -#include "android_keycodes.h" - -struct KeycodeLabel { - const char *literal; - int value; -}; - -static const KeycodeLabel KEYCODES[] = { - { "SOFT_LEFT", 1 }, - { "SOFT_RIGHT", 2 }, - { "HOME", 3 }, - { "BACK", 4 }, - { "CALL", 5 }, - { "ENDCALL", 6 }, - { "0", 7 }, - { "1", 8 }, - { "2", 9 }, - { "3", 10 }, - { "4", 11 }, - { "5", 12 }, - { "6", 13 }, - { "7", 14 }, - { "8", 15 }, - { "9", 16 }, - { "STAR", 17 }, - { "POUND", 18 }, - { "DPAD_UP", 19 }, - { "DPAD_DOWN", 20 }, - { "DPAD_LEFT", 21 }, - { "DPAD_RIGHT", 22 }, - { "DPAD_CENTER", 23 }, - { "VOLUME_UP", 24 }, - { "VOLUME_DOWN", 25 }, - { "POWER", 26 }, - { "CAMERA", 27 }, - { "CLEAR", 28 }, - { "A", 29 }, - { "B", 30 }, - { "C", 31 }, - { "D", 32 }, - { "E", 33 }, - { "F", 34 }, - { "G", 35 }, - { "H", 36 }, - { "I", 37 }, - { "J", 38 }, - { "K", 39 }, - { "L", 40 }, - { "M", 41 }, - { "N", 42 }, - { "O", 43 }, - { "P", 44 }, - { "Q", 45 }, - { "R", 46 }, - { "S", 47 }, - { "T", 48 }, - { "U", 49 }, - { "V", 50 }, - { "W", 51 }, - { "X", 52 }, - { "Y", 53 }, - { "Z", 54 }, - { "COMMA", 55 }, - { "PERIOD", 56 }, - { "ALT_LEFT", 57 }, - { "ALT_RIGHT", 58 }, - { "SHIFT_LEFT", 59 }, - { "SHIFT_RIGHT", 60 }, - { "TAB", 61 }, - { "SPACE", 62 }, - { "SYM", 63 }, - { "EXPLORER", 64 }, - { "ENVELOPE", 65 }, - { "ENTER", 66 }, - { "DEL", 67 }, - { "GRAVE", 68 }, - { "MINUS", 69 }, - { "EQUALS", 70 }, - { "LEFT_BRACKET", 71 }, - { "RIGHT_BRACKET", 72 }, - { "BACKSLASH", 73 }, - { "SEMICOLON", 74 }, - { "APOSTROPHE", 75 }, - { "SLASH", 76 }, - { "AT", 77 }, - { "NUM", 78 }, - { "HEADSETHOOK", 79 }, - { "FOCUS", 80 }, - { "PLUS", 81 }, - { "MENU", 82 }, - { "NOTIFICATION", 83 }, - { "SEARCH", 84 }, - { "MEDIA_PLAY_PAUSE", 85 }, - { "MEDIA_STOP", 86 }, - { "MEDIA_NEXT", 87 }, - { "MEDIA_PREVIOUS", 88 }, - { "MEDIA_REWIND", 89 }, - { "MEDIA_FAST_FORWARD", 90 }, - { "MUTE", 91 }, - { "PAGE_UP", 92 }, - { "PAGE_DOWN", 93 }, - { "PICTSYMBOLS", 94 }, - { "SWITCH_CHARSET", 95 }, - { "BUTTON_A", 96 }, - { "BUTTON_B", 97 }, - { "BUTTON_C", 98 }, - { "BUTTON_X", 99 }, - { "BUTTON_Y", 100 }, - { "BUTTON_Z", 101 }, - { "BUTTON_L1", 102 }, - { "BUTTON_R1", 103 }, - { "BUTTON_L2", 104 }, - { "BUTTON_R2", 105 }, - { "BUTTON_THUMBL", 106 }, - { "BUTTON_THUMBR", 107 }, - { "BUTTON_START", 108 }, - { "BUTTON_SELECT", 109 }, - { "BUTTON_MODE", 110 }, - { "ESCAPE", 111 }, - { "FORWARD_DEL", 112 }, - { "CTRL_LEFT", 113 }, - { "CTRL_RIGHT", 114 }, - { "CAPS_LOCK", 115 }, - { "SCROLL_LOCK", 116 }, - { "META_LEFT", 117 }, - { "META_RIGHT", 118 }, - { "FUNCTION", 119 }, - { "SYSRQ", 120 }, - { "BREAK", 121 }, - { "MOVE_HOME", 122 }, - { "MOVE_END", 123 }, - { "INSERT", 124 }, - { "FORWARD", 125 }, - { "MEDIA_PLAY", 126 }, - { "MEDIA_PAUSE", 127 }, - { "MEDIA_CLOSE", 128 }, - { "MEDIA_EJECT", 129 }, - { "MEDIA_RECORD", 130 }, - { "F1", 131 }, - { "F2", 132 }, - { "F3", 133 }, - { "F4", 134 }, - { "F5", 135 }, - { "F6", 136 }, - { "F7", 137 }, - { "F8", 138 }, - { "F9", 139 }, - { "F10", 140 }, - { "F11", 141 }, - { "F12", 142 }, - { "NUM_LOCK", 143 }, - { "NUMPAD_0", 144 }, - { "NUMPAD_1", 145 }, - { "NUMPAD_2", 146 }, - { "NUMPAD_3", 147 }, - { "NUMPAD_4", 148 }, - { "NUMPAD_5", 149 }, - { "NUMPAD_6", 150 }, - { "NUMPAD_7", 151 }, - { "NUMPAD_8", 152 }, - { "NUMPAD_9", 153 }, - { "NUMPAD_DIVIDE", 154 }, - { "NUMPAD_MULTIPLY", 155 }, - { "NUMPAD_SUBTRACT", 156 }, - { "NUMPAD_ADD", 157 }, - { "NUMPAD_DOT", 158 }, - { "NUMPAD_COMMA", 159 }, - { "NUMPAD_ENTER", 160 }, - { "NUMPAD_EQUALS", 161 }, - { "NUMPAD_LEFT_PAREN", 162 }, - { "NUMPAD_RIGHT_PAREN", 163 }, - { "VOLUME_MUTE", 164 }, - { "INFO", 165 }, - { "CHANNEL_UP", 166 }, - { "CHANNEL_DOWN", 167 }, - { "ZOOM_IN", 168 }, - { "ZOOM_OUT", 169 }, - { "TV", 170 }, - { "WINDOW", 171 }, - { "GUIDE", 172 }, - { "DVR", 173 }, - { "BOOKMARK", 174 }, - { "CAPTIONS", 175 }, - { "SETTINGS", 176 }, - { "TV_POWER", 177 }, - { "TV_INPUT", 178 }, - { "STB_POWER", 179 }, - { "STB_INPUT", 180 }, - { "AVR_POWER", 181 }, - { "AVR_INPUT", 182 }, - { "PROG_RED", 183 }, - { "PROG_GREEN", 184 }, - { "PROG_YELLOW", 185 }, - { "PROG_BLUE", 186 }, - { "APP_SWITCH", 187 }, - { "BUTTON_1", 188 }, - { "BUTTON_2", 189 }, - { "BUTTON_3", 190 }, - { "BUTTON_4", 191 }, - { "BUTTON_5", 192 }, - { "BUTTON_6", 193 }, - { "BUTTON_7", 194 }, - { "BUTTON_8", 195 }, - { "BUTTON_9", 196 }, - { "BUTTON_10", 197 }, - { "BUTTON_11", 198 }, - { "BUTTON_12", 199 }, - { "BUTTON_13", 200 }, - { "BUTTON_14", 201 }, - { "BUTTON_15", 202 }, - { "BUTTON_16", 203 }, - { "LANGUAGE_SWITCH", 204 }, - { "MANNER_MODE", 205 }, - { "3D_MODE", 206 }, - { "CONTACTS", 207 }, - { "CALENDAR", 208 }, - { "MUSIC", 209 }, - { "CALCULATOR", 210 }, - { "ZENKAKU_HANKAKU", 211 }, - { "EISU", 212 }, - { "MUHENKAN", 213 }, - { "HENKAN", 214 }, - { "KATAKANA_HIRAGANA", 215 }, - { "YEN", 216 }, - { "RO", 217 }, - { "KANA", 218 }, - { "ASSIST", 219 }, - { "BRIGHTNESS_DOWN", 220 }, - { "BRIGHTNESS_UP", 221 }, - { "MEDIA_AUDIO_TRACK", 222 }, - { "SLEEP", 223 }, - { "WAKEUP", 224 }, - { "PAIRING", 225 }, - { "MEDIA_TOP_MENU", 226 }, - { "11", 227 }, - { "12", 228 }, - { "LAST_CHANNEL", 229 }, - { "TV_DATA_SERVICE", 230 }, - { "VOICE_ASSIST", 231 }, - { "TV_RADIO_SERVICE", 232 }, - { "TV_TELETEXT", 233 }, - { "TV_NUMBER_ENTRY", 234 }, - { "TV_TERRESTRIAL_ANALOG", 235 }, - { "TV_TERRESTRIAL_DIGITAL", 236 }, - { "TV_SATELLITE", 237 }, - { "TV_SATELLITE_BS", 238 }, - { "TV_SATELLITE_CS", 239 }, - { "TV_SATELLITE_SERVICE", 240 }, - { "TV_NETWORK", 241 }, - { "TV_ANTENNA_CABLE", 242 }, - { "TV_INPUT_HDMI_1", 243 }, - { "TV_INPUT_HDMI_2", 244 }, - { "TV_INPUT_HDMI_3", 245 }, - { "TV_INPUT_HDMI_4", 246 }, - { "TV_INPUT_COMPOSITE_1", 247 }, - { "TV_INPUT_COMPOSITE_2", 248 }, - { "TV_INPUT_COMPONENT_1", 249 }, - { "TV_INPUT_COMPONENT_2", 250 }, - { "TV_INPUT_VGA_1", 251 }, - { "TV_AUDIO_DESCRIPTION", 252 }, - { "TV_AUDIO_DESCRIPTION_MIX_UP", 253 }, - { "TV_AUDIO_DESCRIPTION_MIX_DOWN", 254 }, - { "TV_ZOOM_MODE", 255 }, - { "TV_CONTENTS_MENU", 256 }, - { "TV_MEDIA_CONTEXT_MENU", 257 }, - { "TV_TIMER_PROGRAMMING", 258 }, - { "HELP", 259 }, - - // NOTE: If you add a new keycode here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. - - { NULL, 0 } -}; - -// NOTE: If you edit these flags, also edit policy flags in Input.h. -static const KeycodeLabel FLAGS[] = { - { "WAKE", 0x00000001 }, - { "WAKE_DROPPED", 0x00000002 }, - { "SHIFT", 0x00000004 }, - { "CAPS_LOCK", 0x00000008 }, - { "ALT", 0x00000010 }, - { "ALT_GR", 0x00000020 }, - { "MENU", 0x00000040 }, - { "LAUNCHER", 0x00000080 }, - { "VIRTUAL", 0x00000100 }, - { "FUNCTION", 0x00000200 }, - { NULL, 0 } -}; - -static const KeycodeLabel AXES[] = { - { "X", 0 }, - { "Y", 1 }, - { "PRESSURE", 2 }, - { "SIZE", 3 }, - { "TOUCH_MAJOR", 4 }, - { "TOUCH_MINOR", 5 }, - { "TOOL_MAJOR", 6 }, - { "TOOL_MINOR", 7 }, - { "ORIENTATION", 8 }, - { "VSCROLL", 9 }, - { "HSCROLL", 10 }, - { "Z", 11 }, - { "RX", 12 }, - { "RY", 13 }, - { "RZ", 14 }, - { "HAT_X", 15 }, - { "HAT_Y", 16 }, - { "LTRIGGER", 17 }, - { "RTRIGGER", 18 }, - { "THROTTLE", 19 }, - { "RUDDER", 20 }, - { "WHEEL", 21 }, - { "GAS", 22 }, - { "BRAKE", 23 }, - { "DISTANCE", 24 }, - { "TILT", 25 }, - { "GENERIC_1", 32 }, - { "GENERIC_2", 33 }, - { "GENERIC_3", 34 }, - { "GENERIC_4", 35 }, - { "GENERIC_5", 36 }, - { "GENERIC_6", 37 }, - { "GENERIC_7", 38 }, - { "GENERIC_8", 39 }, - { "GENERIC_9", 40 }, - { "GENERIC_10", 41 }, - { "GENERIC_11", 42 }, - { "GENERIC_12", 43 }, - { "GENERIC_13", 44 }, - { "GENERIC_14", 45 }, - { "GENERIC_15", 46 }, - { "GENERIC_16", 47 }, - - // NOTE: If you add a new axis here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. - - { NULL, -1 } -}; - -static const KeycodeLabel LEDS[] = { - { "NUM_LOCK", 1}, - { "CAPS_LOCK", 2}, - { "SCROLL_LOCK", 3}, - { "COMPOSE", 4}, - { "KANA", 5}, - { "SLEEP", 6}, - { "SUSPEND", 7}, - { "MUTE", 8}, - { "MISC", 9}, - { "MAIL", 10}, - { "CHARGING", 11}, - { "CONTROLLER_1", 12}, - { "CONTROLLER_2", 13}, - { "CONTROLLER_3", 14}, - { "CONTROLLER_4", 15}, - - // NOTE: If you add new LEDs here, you must also add them to Input.h - { NULL, 0 } -}; - -#endif // _ANDROIDFW_KEYCODE_LABELS_H diff --git a/widget/gonk/libui/PointerController.cpp b/widget/gonk/libui/PointerController.cpp deleted file mode 100644 index ff80a0a9f..000000000 --- a/widget/gonk/libui/PointerController.cpp +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "PointerController" - -//#define LOG_NDEBUG 0 - -// Log debug messages about pointer updates -#define DEBUG_POINTER_UPDATES 0 - -#include "PointerController.h" - -#include "cutils_log.h" - -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkPaint.h> -#include <SkXfermode.h> - -namespace android { - -// --- PointerController --- - -// Time to wait before starting the fade when the pointer is inactive. -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds - -// Time to wait between animation frames. -static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60; - -// Time to spend fading out the spot completely. -static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms - -// Time to spend fading out the pointer completely. -static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms - - -// --- PointerController --- - -PointerController::PointerController(const sp<PointerControllerPolicyInterface>& policy, - const sp<Looper>& looper, const sp<SpriteController>& spriteController) : - mPolicy(policy), mLooper(looper), mSpriteController(spriteController) { - mHandler = new WeakMessageHandler(this); - - AutoMutex _l(mLock); - - mLocked.animationPending = false; - - mLocked.displayWidth = -1; - mLocked.displayHeight = -1; - mLocked.displayOrientation = DISPLAY_ORIENTATION_0; - - mLocked.presentation = PRESENTATION_POINTER; - mLocked.presentationChanged = false; - - mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL; - - mLocked.pointerFadeDirection = 0; - mLocked.pointerX = 0; - mLocked.pointerY = 0; - mLocked.pointerAlpha = 0.0f; // pointer is initially faded - mLocked.pointerSprite = mSpriteController->createSprite(); - mLocked.pointerIconChanged = false; - - mLocked.buttonState = 0; - - loadResources(); -} - -PointerController::~PointerController() { - mLooper->removeMessages(mHandler); - - AutoMutex _l(mLock); - - mLocked.pointerSprite.clear(); - - for (size_t i = 0; i < mLocked.spots.size(); i++) { - delete mLocked.spots.itemAt(i); - } - mLocked.spots.clear(); - mLocked.recycledSprites.clear(); -} - -bool PointerController::getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - AutoMutex _l(mLock); - - return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); -} - -bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { - return false; - } - - *outMinX = 0; - *outMinY = 0; - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - *outMaxX = mLocked.displayHeight - 1; - *outMaxY = mLocked.displayWidth - 1; - break; - default: - *outMaxX = mLocked.displayWidth - 1; - *outMaxY = mLocked.displayHeight - 1; - break; - } - return true; -} - -void PointerController::move(float deltaX, float deltaY) { -#if DEBUG_POINTER_UPDATES - ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); -#endif - if (deltaX == 0.0f && deltaY == 0.0f) { - return; - } - - AutoMutex _l(mLock); - - setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); -} - -void PointerController::setButtonState(int32_t buttonState) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set button state 0x%08x", buttonState); -#endif - AutoMutex _l(mLock); - - if (mLocked.buttonState != buttonState) { - mLocked.buttonState = buttonState; - } -} - -int32_t PointerController::getButtonState() const { - AutoMutex _l(mLock); - - return mLocked.buttonState; -} - -void PointerController::setPosition(float x, float y) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); -#endif - AutoMutex _l(mLock); - - setPositionLocked(x, y); -} - -void PointerController::setPositionLocked(float x, float y) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - if (x <= minX) { - mLocked.pointerX = minX; - } else if (x >= maxX) { - mLocked.pointerX = maxX; - } else { - mLocked.pointerX = x; - } - if (y <= minY) { - mLocked.pointerY = minY; - } else if (y >= maxY) { - mLocked.pointerY = maxY; - } else { - mLocked.pointerY = y; - } - updatePointerLocked(); - } -} - -void PointerController::getPosition(float* outX, float* outY) const { - AutoMutex _l(mLock); - - *outX = mLocked.pointerX; - *outY = mLocked.pointerY; -} - -void PointerController::fade(Transition transition) { - AutoMutex _l(mLock); - - // Remove the inactivity timeout, since we are fading now. - removeInactivityTimeoutLocked(); - - // Start fading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 0.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = -1; - startAnimationLocked(); - } -} - -void PointerController::unfade(Transition transition) { - AutoMutex _l(mLock); - - // Always reset the inactivity timer. - resetInactivityTimeoutLocked(); - - // Start unfading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 1.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = 1; - startAnimationLocked(); - } -} - -void PointerController::setPresentation(Presentation presentation) { - AutoMutex _l(mLock); - - if (mLocked.presentation != presentation) { - mLocked.presentation = presentation; - mLocked.presentationChanged = true; - - if (presentation != PRESENTATION_SPOT) { - fadeOutAndReleaseAllSpotsLocked(); - } - - updatePointerLocked(); - } -} - -void PointerController::setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { -#if DEBUG_POINTER_UPDATES - ALOGD("setSpots: idBits=%08x", spotIdBits.value); - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, - c.getAxisValue(AMOTION_EVENT_AXIS_X), - c.getAxisValue(AMOTION_EVENT_AXIS_Y), - c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - - AutoMutex _l(mLock); - - mSpriteController->openTransaction(); - - // Add or move spots for fingers that are down. - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 - ? mResources.spotTouch : mResources.spotHover; - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); - - Spot* spot = getSpotLocked(id); - if (!spot) { - spot = createAndAddSpotLocked(id); - } - - spot->updateSprite(&icon, x, y); - } - - // Remove spots for fingers that went up. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id != Spot::INVALID_ID - && !spotIdBits.hasBit(spot->id)) { - fadeOutAndReleaseSpotLocked(spot); - } - } - - mSpriteController->closeTransaction(); -} - -void PointerController::clearSpots() { -#if DEBUG_POINTER_UPDATES - ALOGD("clearSpots"); -#endif - - AutoMutex _l(mLock); - - fadeOutAndReleaseAllSpotsLocked(); -} - -void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { - AutoMutex _l(mLock); - - if (mLocked.inactivityTimeout != inactivityTimeout) { - mLocked.inactivityTimeout = inactivityTimeout; - resetInactivityTimeoutLocked(); - } -} - -void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) { - AutoMutex _l(mLock); - - // Adjust to use the display's unrotated coordinate frame. - if (orientation == DISPLAY_ORIENTATION_90 - || orientation == DISPLAY_ORIENTATION_270) { - int32_t temp = height; - height = width; - width = temp; - } - - if (mLocked.displayWidth != width || mLocked.displayHeight != height) { - mLocked.displayWidth = width; - mLocked.displayHeight = height; - - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - mLocked.pointerX = (minX + maxX) * 0.5f; - mLocked.pointerY = (minY + maxY) * 0.5f; - } else { - mLocked.pointerX = 0; - mLocked.pointerY = 0; - } - - fadeOutAndReleaseAllSpotsLocked(); - } - - if (mLocked.displayOrientation != orientation) { - // Apply offsets to convert from the pixel top-left corner position to the pixel center. - // This creates an invariant frame of reference that we can easily rotate when - // taking into account that the pointer may be located at fractional pixel offsets. - float x = mLocked.pointerX + 0.5f; - float y = mLocked.pointerY + 0.5f; - float temp; - - // Undo the previous rotation. - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = mLocked.displayWidth - y; - y = temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = y; - y = mLocked.displayHeight - temp; - break; - } - - // Perform the new rotation. - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = y; - y = mLocked.displayWidth - temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = mLocked.displayHeight - y; - y = temp; - break; - } - - // Apply offsets to convert from the pixel center to the pixel top-left corner position - // and save the results. - mLocked.pointerX = x - 0.5f; - mLocked.pointerY = y - 0.5f; - mLocked.displayOrientation = orientation; - } - - updatePointerLocked(); -} - -void PointerController::setPointerIcon(const SpriteIcon& icon) { - AutoMutex _l(mLock); - - mLocked.pointerIcon = icon.copy(); - mLocked.pointerIconChanged = true; - - updatePointerLocked(); -} - -void PointerController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_ANIMATE: - doAnimate(); - break; - case MSG_INACTIVITY_TIMEOUT: - doInactivityTimeout(); - break; - } -} - -void PointerController::doAnimate() { - AutoMutex _l(mLock); - - bool keepAnimating = false; - mLocked.animationPending = false; - nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime; - - // Animate pointer fade. - if (mLocked.pointerFadeDirection < 0) { - mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha <= 0.0f) { - mLocked.pointerAlpha = 0.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } else if (mLocked.pointerFadeDirection > 0) { - mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha >= 1.0f) { - mLocked.pointerAlpha = 1.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } - - // Animate spots that are fading out and being removed. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; - if (spot->alpha <= 0) { - mLocked.spots.removeAt(i--); - releaseSpotLocked(spot); - } else { - spot->sprite->setAlpha(spot->alpha); - keepAnimating = true; - } - } - } - - if (keepAnimating) { - startAnimationLocked(); - } -} - -void PointerController::doInactivityTimeout() { - fade(TRANSITION_GRADUAL); -} - -void PointerController::startAnimationLocked() { - if (!mLocked.animationPending) { - mLocked.animationPending = true; - mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); - mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE)); - } -} - -void PointerController::resetInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); - - nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT - ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; - mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::removeInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::updatePointerLocked() { - mSpriteController->openTransaction(); - - mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); - mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); - - if (mLocked.pointerAlpha > 0) { - mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); - mLocked.pointerSprite->setVisible(true); - } else { - mLocked.pointerSprite->setVisible(false); - } - - if (mLocked.pointerIconChanged || mLocked.presentationChanged) { - mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER - ? mLocked.pointerIcon : mResources.spotAnchor); - mLocked.pointerIconChanged = false; - mLocked.presentationChanged = false; - } - - mSpriteController->closeTransaction(); -} - -PointerController::Spot* PointerController::getSpotLocked(uint32_t id) { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == id) { - return spot; - } - } - return NULL; -} - -PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) { - // Remove spots until we have fewer than MAX_SPOTS remaining. - while (mLocked.spots.size() >= MAX_SPOTS) { - Spot* spot = removeFirstFadingSpotLocked(); - if (!spot) { - spot = mLocked.spots.itemAt(0); - mLocked.spots.removeAt(0); - } - releaseSpotLocked(spot); - } - - // Obtain a sprite from the recycled pool. - sp<Sprite> sprite; - if (! mLocked.recycledSprites.isEmpty()) { - sprite = mLocked.recycledSprites.top(); - mLocked.recycledSprites.pop(); - } else { - sprite = mSpriteController->createSprite(); - } - - // Return the new spot. - Spot* spot = new Spot(id, sprite); - mLocked.spots.push(spot); - return spot; -} - -PointerController::Spot* PointerController::removeFirstFadingSpotLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - mLocked.spots.removeAt(i); - return spot; - } - } - return NULL; -} - -void PointerController::releaseSpotLocked(Spot* spot) { - spot->sprite->clearIcon(); - - if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { - mLocked.recycledSprites.push(spot->sprite); - } - - delete spot; -} - -void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { - if (spot->id != Spot::INVALID_ID) { - spot->id = Spot::INVALID_ID; - startAnimationLocked(); - } -} - -void PointerController::fadeOutAndReleaseAllSpotsLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - fadeOutAndReleaseSpotLocked(spot); - } -} - -void PointerController::loadResources() { - mPolicy->loadPointerResources(&mResources); -} - - -// --- PointerController::Spot --- - -void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) { - sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); - sprite->setAlpha(alpha); - sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); - sprite->setPosition(x, y); - - this->x = x; - this->y = y; - - if (icon != lastIcon) { - lastIcon = icon; - if (icon) { - sprite->setIcon(*icon); - sprite->setVisible(true); - } else { - sprite->setVisible(false); - } - } -} - -} // namespace android diff --git a/widget/gonk/libui/PointerController.h b/widget/gonk/libui/PointerController.h deleted file mode 100644 index eb48d9a1f..000000000 --- a/widget/gonk/libui/PointerController.h +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_POINTER_CONTROLLER_H -#define _UI_POINTER_CONTROLLER_H - -#include "SpriteController.h" - -#include <ui/DisplayInfo.h> -#include "Input.h" -#include <utils/BitSet.h> -#include <utils/RefBase.h> -#include <utils/Looper.h> -#include <utils/String8.h> - -#include <SkBitmap.h> - -namespace android { - -/** - * Interface for tracking a mouse / touch pad pointer and touch pad spots. - * - * The spots are sprites on screen that visually represent the positions of - * fingers - * - * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. - */ -class PointerControllerInterface : public virtual RefBase { -protected: - PointerControllerInterface() { } - virtual ~PointerControllerInterface() { } - -public: - /* Gets the bounds of the region that the pointer can traverse. - * Returns true if the bounds are available. */ - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const = 0; - - /* Move the pointer. */ - virtual void move(float deltaX, float deltaY) = 0; - - /* Sets a mask that indicates which buttons are pressed. */ - virtual void setButtonState(int32_t buttonState) = 0; - - /* Gets a mask that indicates which buttons are pressed. */ - virtual int32_t getButtonState() const = 0; - - /* Sets the absolute location of the pointer. */ - virtual void setPosition(float x, float y) = 0; - - /* Gets the absolute location of the pointer. */ - virtual void getPosition(float* outX, float* outY) const = 0; - - enum Transition { - // Fade/unfade immediately. - TRANSITION_IMMEDIATE, - // Fade/unfade gradually. - TRANSITION_GRADUAL, - }; - - /* Fades the pointer out now. */ - virtual void fade(Transition transition) = 0; - - /* Makes the pointer visible if it has faded out. - * The pointer never unfades itself automatically. This method must be called - * by the client whenever the pointer is moved or a button is pressed and it - * wants to ensure that the pointer becomes visible again. */ - virtual void unfade(Transition transition) = 0; - - enum Presentation { - // Show the mouse pointer. - PRESENTATION_POINTER, - // Show spots and a spot anchor in place of the mouse pointer. - PRESENTATION_SPOT, - }; - - /* Sets the mode of the pointer controller. */ - virtual void setPresentation(Presentation presentation) = 0; - - /* Sets the spots for the current gesture. - * The spots are not subject to the inactivity timeout like the pointer - * itself it since they are expected to remain visible for so long as - * the fingers are on the touch pad. - * - * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant. - * For spotCoords, pressure != 0 indicates that the spot's location is being - * pressed (not hovering). - */ - virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits) = 0; - - /* Removes all spots. */ - virtual void clearSpots() = 0; -}; - - -/* - * Pointer resources. - */ -struct PointerResources { - SpriteIcon spotHover; - SpriteIcon spotTouch; - SpriteIcon spotAnchor; -}; - - -/* - * Pointer controller policy interface. - * - * The pointer controller policy is used by the pointer controller to interact with - * the Window Manager and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class PointerControllerPolicyInterface : public virtual RefBase { -protected: - PointerControllerPolicyInterface() { } - virtual ~PointerControllerPolicyInterface() { } - -public: - virtual void loadPointerResources(PointerResources* outResources) = 0; -}; - - -/* - * Tracks pointer movements and draws the pointer sprite to a surface. - * - * Handles pointer acceleration and animation. - */ -class PointerController : public PointerControllerInterface, public MessageHandler { -protected: - virtual ~PointerController(); - -public: - enum InactivityTimeout { - INACTIVITY_TIMEOUT_NORMAL = 0, - INACTIVITY_TIMEOUT_SHORT = 1, - }; - - PointerController(const sp<PointerControllerPolicyInterface>& policy, - const sp<Looper>& looper, const sp<SpriteController>& spriteController); - - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; - virtual void move(float deltaX, float deltaY); - virtual void setButtonState(int32_t buttonState); - virtual int32_t getButtonState() const; - virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; - virtual void fade(Transition transition); - virtual void unfade(Transition transition); - - virtual void setPresentation(Presentation presentation); - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits); - virtual void clearSpots(); - - void setDisplayViewport(int32_t width, int32_t height, int32_t orientation); - void setPointerIcon(const SpriteIcon& icon); - void setInactivityTimeout(InactivityTimeout inactivityTimeout); - -private: - static const size_t MAX_RECYCLED_SPRITES = 12; - static const size_t MAX_SPOTS = 12; - - enum { - MSG_ANIMATE, - MSG_INACTIVITY_TIMEOUT, - }; - - struct Spot { - static const uint32_t INVALID_ID = 0xffffffff; - - uint32_t id; - sp<Sprite> sprite; - float alpha; - float scale; - float x, y; - - inline Spot(uint32_t id, const sp<Sprite>& sprite) - : id(id), sprite(sprite), alpha(1.0f), scale(1.0f), - x(0.0f), y(0.0f), lastIcon(NULL) { } - - void updateSprite(const SpriteIcon* icon, float x, float y); - - private: - const SpriteIcon* lastIcon; - }; - - mutable Mutex mLock; - - sp<PointerControllerPolicyInterface> mPolicy; - sp<Looper> mLooper; - sp<SpriteController> mSpriteController; - sp<WeakMessageHandler> mHandler; - - PointerResources mResources; - - struct Locked { - bool animationPending; - nsecs_t animationTime; - - int32_t displayWidth; - int32_t displayHeight; - int32_t displayOrientation; - - InactivityTimeout inactivityTimeout; - - Presentation presentation; - bool presentationChanged; - - int32_t pointerFadeDirection; - float pointerX; - float pointerY; - float pointerAlpha; - sp<Sprite> pointerSprite; - SpriteIcon pointerIcon; - bool pointerIconChanged; - - int32_t buttonState; - - Vector<Spot*> spots; - Vector<sp<Sprite> > recycledSprites; - } mLocked; - - bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; - void setPositionLocked(float x, float y); - - void handleMessage(const Message& message); - void doAnimate(); - void doInactivityTimeout(); - - void startAnimationLocked(); - - void resetInactivityTimeoutLocked(); - void removeInactivityTimeoutLocked(); - void updatePointerLocked(); - - Spot* getSpotLocked(uint32_t id); - Spot* createAndAddSpotLocked(uint32_t id); - Spot* removeFirstFadingSpotLocked(); - void releaseSpotLocked(Spot* spot); - void fadeOutAndReleaseSpotLocked(Spot* spot); - void fadeOutAndReleaseAllSpotsLocked(); - - void loadResources(); -}; - -} // namespace android - -#endif // _UI_POINTER_CONTROLLER_H diff --git a/widget/gonk/libui/PowerManager.h b/widget/gonk/libui/PowerManager.h deleted file mode 100644 index ba98db07c..000000000 --- a/widget/gonk/libui/PowerManager.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_POWER_MANAGER_H -#define _ANDROIDFW_POWER_MANAGER_H - - -namespace android { - -enum { - USER_ACTIVITY_EVENT_OTHER = 0, - USER_ACTIVITY_EVENT_BUTTON = 1, - USER_ACTIVITY_EVENT_TOUCH = 2, - - USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_TOUCH, // Last valid event code. -}; - -} // namespace android - -#endif // _ANDROIDFW_POWER_MANAGER_H diff --git a/widget/gonk/libui/SpriteController.cpp b/widget/gonk/libui/SpriteController.cpp deleted file mode 100644 index 8677476b1..000000000 --- a/widget/gonk/libui/SpriteController.cpp +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Sprites" - -//#define LOG_NDEBUG 0 - -#include "SpriteController.h" - -#include "cutils_log.h" -#include <utils/String8.h> -#ifdef HAVE_ANDROID_OS -#include <gui/Surface.h> -#endif - -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <SkColor.h> -#include <SkPaint.h> -#include <SkXfermode.h> -#include <android/native_window.h> - -namespace android { - -// --- SpriteController --- - -SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) : - mLooper(looper), mOverlayLayer(overlayLayer) { -#ifdef HAVE_ANDROID_OS - mHandler = new WeakMessageHandler(this); -#endif - - mLocked.transactionNestingCount = 0; - mLocked.deferredSpriteUpdate = false; -} - -SpriteController::~SpriteController() { -#ifdef HAVE_ANDROID_OS - mLooper->removeMessages(mHandler); - - if (mSurfaceComposerClient != NULL) { - mSurfaceComposerClient->dispose(); - mSurfaceComposerClient.clear(); - } -#endif -} - -sp<Sprite> SpriteController::createSprite() { - return new SpriteImpl(this); -} - -void SpriteController::openTransaction() { - AutoMutex _l(mLock); - - mLocked.transactionNestingCount += 1; -} - -void SpriteController::closeTransaction() { - AutoMutex _l(mLock); - - LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0, - "Sprite closeTransaction() called but there is no open sprite transaction"); - - mLocked.transactionNestingCount -= 1; - if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) { - mLocked.deferredSpriteUpdate = false; -#ifdef HAVE_ANDROID_OS - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); -#endif - } -} - -void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) { - bool wasEmpty = mLocked.invalidatedSprites.isEmpty(); - mLocked.invalidatedSprites.push(sprite); - if (wasEmpty) { - if (mLocked.transactionNestingCount != 0) { - mLocked.deferredSpriteUpdate = true; - } else { -#ifdef HAVE_ANDROID_OS - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); -#endif - } - } -} - -#ifdef HAVE_ANDROID_OS -void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) { - bool wasEmpty = mLocked.disposedSurfaces.isEmpty(); - mLocked.disposedSurfaces.push(surfaceControl); - if (wasEmpty) { - mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); - } -} - -void SpriteController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_UPDATE_SPRITES: - doUpdateSprites(); - break; - case MSG_DISPOSE_SURFACES: - doDisposeSurfaces(); - break; - } -} -#endif - -void SpriteController::doUpdateSprites() { - // Collect information about sprite updates. - // Each sprite update record includes a reference to its associated sprite so we can - // be certain the sprites will not be deleted while this function runs. Sprites - // may invalidate themselves again during this time but we will handle those changes - // in the next iteration. - Vector<SpriteUpdate> updates; - size_t numSprites; - { // acquire lock - AutoMutex _l(mLock); - - numSprites = mLocked.invalidatedSprites.size(); - for (size_t i = 0; i < numSprites; i++) { - const sp<SpriteImpl>& sprite = mLocked.invalidatedSprites.itemAt(i); - - updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); - sprite->resetDirtyLocked(); - } - mLocked.invalidatedSprites.clear(); - } // release lock - - // Create missing surfaces. - bool surfaceChanged = false; -#ifdef HAVE_ANDROID_OS - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { - update.state.surfaceWidth = update.state.icon.bitmap.width(); - update.state.surfaceHeight = update.state.icon.bitmap.height(); - update.state.surfaceDrawn = false; - update.state.surfaceVisible = false; - update.state.surfaceControl = obtainSurface( - update.state.surfaceWidth, update.state.surfaceHeight); - if (update.state.surfaceControl != NULL) { - update.surfaceChanged = surfaceChanged = true; - } - } - } -#endif - - // Resize sprites if needed, inside a global transaction. -#ifdef HAVE_ANDROID_OS - bool haveGlobalTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { - int32_t desiredWidth = update.state.icon.bitmap.width(); - int32_t desiredHeight = update.state.icon.bitmap.height(); - if (update.state.surfaceWidth < desiredWidth - || update.state.surfaceHeight < desiredHeight) { - if (!haveGlobalTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveGlobalTransaction = true; - } - - status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); - if (status) { - ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d", - status, update.state.surfaceWidth, update.state.surfaceHeight, - desiredWidth, desiredHeight); - } else { - update.state.surfaceWidth = desiredWidth; - update.state.surfaceHeight = desiredHeight; - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - - if (update.state.surfaceVisible) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface after resize.", status); - } else { - update.state.surfaceVisible = false; - } - } - } - } - } - } -#endif -#ifdef HAVE_ANDROID_OS - if (haveGlobalTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } -#endif - - // Redraw sprites if needed. - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - } - -#ifdef HAVE_ANDROID_OS - if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn - && update.state.wantSurfaceVisible()) { - sp<Surface> surface = update.state.surfaceControl->getSurface(); - ANativeWindow_Buffer outBuffer; - status_t status = surface->lock(&outBuffer, NULL); - if (status) { - ALOGE("Error %d locking sprite surface before drawing.", status); - } else { - SkBitmap surfaceBitmap; - ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); - surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, - outBuffer.width, outBuffer.height, bpr); - surfaceBitmap.setPixels(outBuffer.bits); - - SkCanvas surfaceCanvas(surfaceBitmap); - - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); - - if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0, - outBuffer.width, update.state.icon.bitmap.height(), paint); - } - if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(), - outBuffer.width, outBuffer.height, paint); - } - - status = surface->unlockAndPost(); - if (status) { - ALOGE("Error %d unlocking and posting sprite surface after drawing.", status); - } else { - update.state.surfaceDrawn = true; - update.surfaceChanged = surfaceChanged = true; - } - } - } -#endif - } - -#ifdef HAVE_ANDROID_OS - // Set sprite surface properties and make them visible. - bool haveTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() - && update.state.surfaceDrawn; - bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; - bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; - if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden - || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA - | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER - | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { - status_t status; - if (!haveTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveTransaction = true; - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { - status = update.state.surfaceControl->setAlpha(update.state.alpha); - if (status) { - ALOGE("Error %d setting sprite surface alpha.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & (DIRTY_POSITION - | DIRTY_HOTSPOT)))) { - status = update.state.surfaceControl->setPosition( - update.state.positionX - update.state.icon.hotSpotX, - update.state.positionY - update.state.icon.hotSpotY); - if (status) { - ALOGE("Error %d setting sprite surface position.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible - || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { - status = update.state.surfaceControl->setMatrix( - update.state.transformationMatrix.dsdx, - update.state.transformationMatrix.dtdx, - update.state.transformationMatrix.dsdy, - update.state.transformationMatrix.dtdy); - if (status) { - ALOGE("Error %d setting sprite surface transformation matrix.", status); - } - } - - int32_t surfaceLayer = mOverlayLayer + update.state.layer; - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { - status = update.state.surfaceControl->setLayer(surfaceLayer); - if (status) { - ALOGE("Error %d setting sprite surface layer.", status); - } - } - - if (becomingVisible) { - status = update.state.surfaceControl->show(); - if (status) { - ALOGE("Error %d showing sprite surface.", status); - } else { - update.state.surfaceVisible = true; - update.surfaceChanged = surfaceChanged = true; - } - } else if (becomingHidden) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface.", status); - } else { - update.state.surfaceVisible = false; - update.surfaceChanged = surfaceChanged = true; - } - } - } - } -#endif - -#ifdef HAVE_ANDROID_OS - if (haveTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } -#endif - -#ifdef HAVE_ANDROID_OS - // If any surfaces were changed, write back the new surface properties to the sprites. - if (surfaceChanged) { // acquire lock - AutoMutex _l(mLock); - - for (size_t i = 0; i < numSprites; i++) { - const SpriteUpdate& update = updates.itemAt(i); - - if (update.surfaceChanged) { - update.sprite->setSurfaceLocked(update.state.surfaceControl, - update.state.surfaceWidth, update.state.surfaceHeight, - update.state.surfaceDrawn, update.state.surfaceVisible); - } - } - } // release lock -#endif - - // Clear the sprite update vector outside the lock. It is very important that - // we do not clear sprite references inside the lock since we could be releasing - // the last remaining reference to the sprite here which would result in the - // sprite being deleted and the lock being reacquired by the sprite destructor - // while already held. - updates.clear(); -} - -void SpriteController::doDisposeSurfaces() { -#ifdef HAVE_ANDROID_OS - // Collect disposed surfaces. - Vector<sp<SurfaceControl> > disposedSurfaces; - { // acquire lock - AutoMutex _l(mLock); - - disposedSurfaces = mLocked.disposedSurfaces; - mLocked.disposedSurfaces.clear(); - } // release lock - - // Release the last reference to each surface outside of the lock. - // We don't want the surfaces to be deleted while we are holding our lock. - disposedSurfaces.clear(); -#endif -} - -void SpriteController::ensureSurfaceComposerClient() { -#ifdef HAVE_ANDROID_OS - if (mSurfaceComposerClient == NULL) { - mSurfaceComposerClient = new SurfaceComposerClient(); - } -#endif -} - -#ifdef HAVE_ANDROID_OS -sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) { - ensureSurfaceComposerClient(); - - sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface( - String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden); - if (surfaceControl == NULL || !surfaceControl->isValid()) { - ALOGE("Error creating sprite surface."); - return NULL; - } - return surfaceControl; -} -#endif - - -// --- SpriteController::SpriteImpl --- - -SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) : - mController(controller) { -} - -SpriteController::SpriteImpl::~SpriteImpl() { - AutoMutex _m(mController->mLock); - -#ifdef HAVE_ANDROID_OS - // Let the controller take care of deleting the last reference to sprite - // surfaces so that we do not block the caller on an IPC here. - if (mLocked.state.surfaceControl != NULL) { - mController->disposeSurfaceLocked(mLocked.state.surfaceControl); - mLocked.state.surfaceControl.clear(); - } -#endif -} - -void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { - AutoMutex _l(mController->mLock); - -#ifdef HAVE_ANDROID_OS - uint32_t dirty; - if (icon.isValid()) { - icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config); - - if (!mLocked.state.icon.isValid() - || mLocked.state.icon.hotSpotX != icon.hotSpotX - || mLocked.state.icon.hotSpotY != icon.hotSpotY) { - mLocked.state.icon.hotSpotX = icon.hotSpotX; - mLocked.state.icon.hotSpotY = icon.hotSpotY; - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - dirty = DIRTY_BITMAP; - } - } else if (mLocked.state.icon.isValid()) { - mLocked.state.icon.bitmap.reset(); - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - return; // setting to invalid icon and already invalid so nothing to do - } - - invalidateLocked(dirty); -#endif -} - -void SpriteController::SpriteImpl::setVisible(bool visible) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.visible != visible) { - mLocked.state.visible = visible; - invalidateLocked(DIRTY_VISIBILITY); - } -} - -void SpriteController::SpriteImpl::setPosition(float x, float y) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.positionX != x || mLocked.state.positionY != y) { - mLocked.state.positionX = x; - mLocked.state.positionY = y; - invalidateLocked(DIRTY_POSITION); - } -} - -void SpriteController::SpriteImpl::setLayer(int32_t layer) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.layer != layer) { - mLocked.state.layer = layer; - invalidateLocked(DIRTY_LAYER); - } -} - -void SpriteController::SpriteImpl::setAlpha(float alpha) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.alpha != alpha) { - mLocked.state.alpha = alpha; - invalidateLocked(DIRTY_ALPHA); - } -} - -void SpriteController::SpriteImpl::setTransformationMatrix( - const SpriteTransformationMatrix& matrix) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.transformationMatrix != matrix) { - mLocked.state.transformationMatrix = matrix; - invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); - } -} - -void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { - bool wasDirty = mLocked.state.dirty; - mLocked.state.dirty |= dirty; - - if (!wasDirty) { - mController->invalidateSpriteLocked(this); - } -} - -} // namespace android diff --git a/widget/gonk/libui/SpriteController.h b/widget/gonk/libui/SpriteController.h deleted file mode 100644 index 4926095ec..000000000 --- a/widget/gonk/libui/SpriteController.h +++ /dev/null @@ -1,319 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * 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. - */ - -#ifndef _UI_SPRITES_H -#define _UI_SPRITES_H - -#include <utils/RefBase.h> -#include <utils/Looper.h> - -#ifdef HAVE_ANDROID_OS -#include <gui/SurfaceComposerClient.h> -#endif - -#include <SkBitmap.h> - -namespace android { - -/* - * Transformation matrix for a sprite. - */ -struct SpriteTransformationMatrix { - inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { } - inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) : - dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { } - - float dsdx; - float dtdx; - float dsdy; - float dtdy; - - inline bool operator== (const SpriteTransformationMatrix& other) { - return dsdx == other.dsdx - && dtdx == other.dtdx - && dsdy == other.dsdy - && dtdy == other.dtdy; - } - - inline bool operator!= (const SpriteTransformationMatrix& other) { - return !(*this == other); - } -}; - -/* - * Icon that a sprite displays, including its hotspot. - */ -struct SpriteIcon { - inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } -#ifdef HAVE_ANDROID_OS - inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : - bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } - - SkBitmap bitmap; -#endif - float hotSpotX; - float hotSpotY; - - inline SpriteIcon copy() const { -#ifdef HAVE_ANDROID_OS - SkBitmap bitmapCopy; - bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config); - return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); -#else - return SpriteIcon(); -#endif - } - - inline void reset() { -#ifdef HAVE_ANDROID_OS - bitmap.reset(); - hotSpotX = 0; - hotSpotY = 0; -#endif - } - - inline bool isValid() const { -#ifdef HAVE_ANDROID_OS - return !bitmap.isNull() && !bitmap.empty(); -#else - return false; -#endif - } -}; - -/* - * A sprite is a simple graphical object that is displayed on-screen above other layers. - * The basic sprite class is an interface. - * The implementation is provided by the sprite controller. - */ -class Sprite : public RefBase { -protected: - Sprite() { } - virtual ~Sprite() { } - -public: - enum { - // The base layer for pointer sprites. - BASE_LAYER_POINTER = 0, // reserve space for 1 pointer - - // The base layer for spot sprites. - BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots - }; - - /* Sets the bitmap that is drawn by the sprite. - * The sprite retains a copy of the bitmap for subsequent rendering. */ - virtual void setIcon(const SpriteIcon& icon) = 0; - - inline void clearIcon() { - setIcon(SpriteIcon()); - } - - /* Sets whether the sprite is visible. */ - virtual void setVisible(bool visible) = 0; - - /* Sets the sprite position on screen, relative to the sprite's hot spot. */ - virtual void setPosition(float x, float y) = 0; - - /* Sets the layer of the sprite, relative to the system sprite overlay layer. - * Layer 0 is the overlay layer, > 0 appear above this layer. */ - virtual void setLayer(int32_t layer) = 0; - - /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */ - virtual void setAlpha(float alpha) = 0; - - /* Sets the sprite transformation matrix. */ - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0; -}; - -/* - * Displays sprites on the screen. - * - * This interface is used by PointerController and SpotController to draw pointers or - * spot representations of fingers. It is not intended for general purpose use - * by other components. - * - * All sprite position updates and rendering is performed asynchronously. - * - * Clients are responsible for animating sprites by periodically updating their properties. - */ -class SpriteController : public MessageHandler { -protected: - virtual ~SpriteController(); - -public: - SpriteController(const sp<Looper>& looper, int32_t overlayLayer); - - /* Creates a new sprite, initially invisible. */ - sp<Sprite> createSprite(); - - /* Opens or closes a transaction to perform a batch of sprite updates as part of - * a single operation such as setPosition and setAlpha. It is not necessary to - * open a transaction when updating a single property. - * Calls to openTransaction() nest and must be matched by an equal number - * of calls to closeTransaction(). */ - void openTransaction(); - void closeTransaction(); - -private: - enum { - MSG_UPDATE_SPRITES, - MSG_DISPOSE_SURFACES, - }; - - enum { - DIRTY_BITMAP = 1 << 0, - DIRTY_ALPHA = 1 << 1, - DIRTY_POSITION = 1 << 2, - DIRTY_TRANSFORMATION_MATRIX = 1 << 3, - DIRTY_LAYER = 1 << 4, - DIRTY_VISIBILITY = 1 << 5, - DIRTY_HOTSPOT = 1 << 6, - }; - - /* Describes the state of a sprite. - * This structure is designed so that it can be copied during updates so that - * surfaces can be resized and redrawn without blocking the client by holding a lock - * on the sprites for a long time. - * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ - struct SpriteState { - inline SpriteState() : - dirty(0), visible(false), - positionX(0), positionY(0), layer(0), alpha(1.0f), - surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) { - } - - uint32_t dirty; - - SpriteIcon icon; - bool visible; - float positionX; - float positionY; - int32_t layer; - float alpha; - SpriteTransformationMatrix transformationMatrix; - -#ifdef HAVE_ANDROID_OS - sp<SurfaceControl> surfaceControl; -#endif - int32_t surfaceWidth; - int32_t surfaceHeight; - bool surfaceDrawn; - bool surfaceVisible; - - inline bool wantSurfaceVisible() const { - return visible && alpha > 0.0f && icon.isValid(); - } - }; - - /* Client interface for a sprite. - * Requests acquire a lock on the controller, update local state and request the - * controller to invalidate the sprite. - * The real heavy lifting of creating, resizing and redrawing surfaces happens - * asynchronously with no locks held except in short critical section to copy - * the sprite state before the work and update the sprite surface control afterwards. - */ - class SpriteImpl : public Sprite { - protected: - virtual ~SpriteImpl(); - - public: - SpriteImpl(const sp<SpriteController> controller); - - virtual void setIcon(const SpriteIcon& icon); - virtual void setVisible(bool visible); - virtual void setPosition(float x, float y); - virtual void setLayer(int32_t layer); - virtual void setAlpha(float alpha); - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix); - - inline const SpriteState& getStateLocked() const { - return mLocked.state; - } - - inline void resetDirtyLocked() { - mLocked.state.dirty = 0; - } - -#ifdef HAVE_ANDROID_OS - inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl, - int32_t width, int32_t height, bool drawn, bool visible) { - mLocked.state.surfaceControl = surfaceControl; - mLocked.state.surfaceWidth = width; - mLocked.state.surfaceHeight = height; - mLocked.state.surfaceDrawn = drawn; - mLocked.state.surfaceVisible = visible; - } -#endif - - private: - sp<SpriteController> mController; - - struct Locked { - SpriteState state; - } mLocked; // guarded by mController->mLock - - void invalidateLocked(uint32_t dirty); - }; - - /* Stores temporary information collected during the sprite update cycle. */ - struct SpriteUpdate { - inline SpriteUpdate() : surfaceChanged(false) { } - inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) : - sprite(sprite), state(state), surfaceChanged(false) { - } - - sp<SpriteImpl> sprite; - SpriteState state; - bool surfaceChanged; - }; - - mutable Mutex mLock; - - sp<Looper> mLooper; - const int32_t mOverlayLayer; -#ifdef HAVE_ANDROID_OS - sp<WeakMessageHandler> mHandler; - - sp<SurfaceComposerClient> mSurfaceComposerClient; -#endif - - struct Locked { - Vector<sp<SpriteImpl> > invalidatedSprites; -#ifdef HAVE_ANDROID_OS - Vector<sp<SurfaceControl> > disposedSurfaces; -#endif - uint32_t transactionNestingCount; - bool deferredSpriteUpdate; - } mLocked; // guarded by mLock - - void invalidateSpriteLocked(const sp<SpriteImpl>& sprite); -#ifdef HAVE_ANDROID_OS - void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl); - - void handleMessage(const Message& message); -#endif - void doUpdateSprites(); - void doDisposeSurfaces(); - - void ensureSurfaceComposerClient(); -#ifdef HAVE_ANDROID_OS - sp<SurfaceControl> obtainSurface(int32_t width, int32_t height); -#endif -}; - -} // namespace android - -#endif // _UI_SPRITES_H diff --git a/widget/gonk/libui/Tokenizer.cpp b/widget/gonk/libui/Tokenizer.cpp deleted file mode 100644 index 2f585cb4e..000000000 --- a/widget/gonk/libui/Tokenizer.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "Tokenizer" -#include "cutils_log.h" - -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include "Tokenizer.h" - -// Enables debug output for the tokenizer. -#define DEBUG_TOKENIZER 0 - - -namespace android { - -static inline bool isDelimiter(char ch, const char* delimiters) { - return strchr(delimiters, ch) != NULL; -} - -Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, - bool ownBuffer, size_t length) : - mFilename(filename), mFileMap(fileMap), - mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length), - mCurrent(buffer), mLineNumber(1) { -} - -Tokenizer::~Tokenizer() { - if (mFileMap) { - mFileMap->release(); - } - if (mOwnBuffer) { - delete[] mBuffer; - } -} - -status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { - *outTokenizer = NULL; - - int result = NO_ERROR; - int fd = ::open(filename.string(), O_RDONLY); - if (fd < 0) { - result = -errno; - ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno)); - } else { - struct stat stat; - if (fstat(fd, &stat)) { - result = -errno; - ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); - } else { - size_t length = size_t(stat.st_size); - - FileMap* fileMap = new FileMap(); - bool ownBuffer = false; - char* buffer; - if (fileMap->create(NULL, fd, 0, length, true)) { - fileMap->advise(FileMap::SEQUENTIAL); - buffer = static_cast<char*>(fileMap->getDataPtr()); - } else { - fileMap->release(); - fileMap = NULL; - - // Fall back to reading into a buffer since we can't mmap files in sysfs. - // The length we obtained from stat is wrong too (it will always be 4096) - // so we must trust that read will read the entire file. - buffer = new char[length]; - ownBuffer = true; - ssize_t nrd = read(fd, buffer, length); - if (nrd < 0) { - result = -errno; - ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); - delete[] buffer; - buffer = NULL; - } else { - length = size_t(nrd); - } - } - - if (!result) { - *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length); - } - } - close(fd); - } - return result; -} - -status_t Tokenizer::fromContents(const String8& filename, - const char* contents, Tokenizer** outTokenizer) { - *outTokenizer = new Tokenizer(filename, NULL, - const_cast<char*>(contents), false, strlen(contents)); - return OK; -} - -String8 Tokenizer::getLocation() const { - String8 result; - result.appendFormat("%s:%d", mFilename.string(), mLineNumber); - return result; -} - -String8 Tokenizer::peekRemainderOfLine() const { - const char* end = getEnd(); - const char* eol = mCurrent; - while (eol != end) { - char ch = *eol; - if (ch == '\n') { - break; - } - eol += 1; - } - return String8(mCurrent, eol - mCurrent); -} - -String8 Tokenizer::nextToken(const char* delimiters) { -#if DEBUG_TOKENIZER - ALOGD("nextToken"); -#endif - const char* end = getEnd(); - const char* tokenStart = mCurrent; - while (mCurrent != end) { - char ch = *mCurrent; - if (ch == '\n' || isDelimiter(ch, delimiters)) { - break; - } - mCurrent += 1; - } - return String8(tokenStart, mCurrent - tokenStart); -} - -void Tokenizer::nextLine() { -#if DEBUG_TOKENIZER - ALOGD("nextLine"); -#endif - const char* end = getEnd(); - while (mCurrent != end) { - char ch = *(mCurrent++); - if (ch == '\n') { - mLineNumber += 1; - break; - } - } -} - -void Tokenizer::skipDelimiters(const char* delimiters) { -#if DEBUG_TOKENIZER - ALOGD("skipDelimiters"); -#endif - const char* end = getEnd(); - while (mCurrent != end) { - char ch = *mCurrent; - if (ch == '\n' || !isDelimiter(ch, delimiters)) { - break; - } - mCurrent += 1; - } -} - -} // namespace android diff --git a/widget/gonk/libui/Tokenizer.h b/widget/gonk/libui/Tokenizer.h deleted file mode 100644 index bb25f374c..000000000 --- a/widget/gonk/libui/Tokenizer.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _UTILS_TOKENIZER_H -#define _UTILS_TOKENIZER_H - -#include <assert.h> -#include <utils/Errors.h> -#include <utils/FileMap.h> -#include <utils/String8.h> - -namespace android { - -/** - * A simple tokenizer for loading and parsing ASCII text files line by line. - */ -class Tokenizer { - Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, - bool ownBuffer, size_t length); - -public: - ~Tokenizer(); - - /** - * Opens a file and maps it into memory. - * - * Returns NO_ERROR and a tokenizer for the file, if successful. - * Otherwise returns an error and sets outTokenizer to NULL. - */ - static status_t open(const String8& filename, Tokenizer** outTokenizer); - - /** - * Prepares to tokenize the contents of a string. - * - * Returns NO_ERROR and a tokenizer for the string, if successful. - * Otherwise returns an error and sets outTokenizer to NULL. - */ - static status_t fromContents(const String8& filename, - const char* contents, Tokenizer** outTokenizer); - - /** - * Returns true if at the end of the file. - */ - inline bool isEof() const { return mCurrent == getEnd(); } - - /** - * Returns true if at the end of the line or end of the file. - */ - inline bool isEol() const { return isEof() || *mCurrent == '\n'; } - - /** - * Gets the name of the file. - */ - inline String8 getFilename() const { return mFilename; } - - /** - * Gets a 1-based line number index for the current position. - */ - inline int32_t getLineNumber() const { return mLineNumber; } - - /** - * Formats a location string consisting of the filename and current line number. - * Returns a string like "MyFile.txt:33". - */ - String8 getLocation() const; - - /** - * Gets the character at the current position. - * Returns null at end of file. - */ - inline char peekChar() const { return isEof() ? '\0' : *mCurrent; } - - /** - * Gets the remainder of the current line as a string, excluding the newline character. - */ - String8 peekRemainderOfLine() const; - - /** - * Gets the character at the current position and advances past it. - * Returns null at end of file. - */ - inline char nextChar() { return isEof() ? '\0' : *(mCurrent++); } - - /** - * Gets the next token on this line stopping at the specified delimiters - * or the end of the line whichever comes first and advances past it. - * Also stops at embedded nulls. - * Returns the token or an empty string if the current character is a delimiter - * or is at the end of the line. - */ - String8 nextToken(const char* delimiters); - - /** - * Advances to the next line. - * Does nothing if already at the end of the file. - */ - void nextLine(); - - /** - * Skips over the specified delimiters in the line. - * Also skips embedded nulls. - */ - void skipDelimiters(const char* delimiters); - -private: - Tokenizer(const Tokenizer& other); // not copyable - - String8 mFilename; - FileMap* mFileMap; - char* mBuffer; - bool mOwnBuffer; - size_t mLength; - - const char* mCurrent; - int32_t mLineNumber; - - inline const char* getEnd() const { return mBuffer + mLength; } - -}; - -} // namespace android - -#endif // _UTILS_TOKENIZER_H diff --git a/widget/gonk/libui/Trace.h b/widget/gonk/libui/Trace.h deleted file mode 100644 index 24fbfb602..000000000 --- a/widget/gonk/libui/Trace.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef ANDROID_TRACE_H -#define ANDROID_TRACE_H - -#include <fcntl.h> -#include <stdint.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <cutils/compiler.h> -#include <utils/threads.h> -#include "cutils_trace.h" - -// See <cutils/trace.h> for more ATRACE_* macros. - -// ATRACE_NAME traces the beginning and end of the current scope. To trace -// the correct start and end times this macro should be declared first in the -// scope body. -#define ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name) -// ATRACE_CALL is an ATRACE_NAME that uses the current function name. -#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) - -namespace android { - -class ScopedTrace { -public: -inline ScopedTrace(uint64_t tag, const char* name) - : mTag(tag) { -#ifdef HAVE_ANDROID_OS - atrace_begin(mTag,name); -#endif -} - -inline ~ScopedTrace() { -#ifdef HAVE_ANDROID_OS - atrace_end(mTag); -#endif -} - -private: - uint64_t mTag; -}; - -}; // namespace android - -#endif // ANDROID_TRACE_H diff --git a/widget/gonk/libui/VelocityControl.cpp b/widget/gonk/libui/VelocityControl.cpp deleted file mode 100644 index 31365a220..000000000 --- a/widget/gonk/libui/VelocityControl.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "VelocityControl" -//#define LOG_NDEBUG 0 - -// Log debug messages about acceleration. -#define DEBUG_ACCELERATION 0 - -#include <math.h> -#include <limits.h> - -#include "VelocityControl.h" -#include <utils/BitSet.h> -#include <utils/Timers.h> - -namespace android { - -// --- VelocityControl --- - -const nsecs_t VelocityControl::STOP_TIME; - -VelocityControl::VelocityControl() { - reset(); -} - -void VelocityControl::setParameters(const VelocityControlParameters& parameters) { - mParameters = parameters; - reset(); -} - -void VelocityControl::reset() { - mLastMovementTime = LLONG_MIN; - mRawPosition.x = 0; - mRawPosition.y = 0; - mVelocityTracker.clear(); -} - -void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { - if ((deltaX && *deltaX) || (deltaY && *deltaY)) { - if (eventTime >= mLastMovementTime + STOP_TIME) { -#if DEBUG_ACCELERATION - ALOGD("VelocityControl: stopped, last movement was %0.3fms ago", - (eventTime - mLastMovementTime) * 0.000001f); -#endif - reset(); - } - - mLastMovementTime = eventTime; - if (deltaX) { - mRawPosition.x += *deltaX; - } - if (deltaY) { - mRawPosition.y += *deltaY; - } - mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); - - float vx, vy; - float scale = mParameters.scale; - if (mVelocityTracker.getVelocity(0, &vx, &vy)) { - float speed = hypotf(vx, vy) * scale; - if (speed >= mParameters.highThreshold) { - // Apply full acceleration above the high speed threshold. - scale *= mParameters.acceleration; - } else if (speed > mParameters.lowThreshold) { - // Linearly interpolate the acceleration to apply between the low and high - // speed thresholds. - scale *= 1 + (speed - mParameters.lowThreshold) - / (mParameters.highThreshold - mParameters.lowThreshold) - * (mParameters.acceleration - 1); - } - -#if DEBUG_ACCELERATION - ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " - "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", - mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, - mParameters.acceleration, - vx, vy, speed, scale / mParameters.scale); -#endif - } else { -#if DEBUG_ACCELERATION - ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", - mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, - mParameters.acceleration); -#endif - } - - if (deltaX) { - *deltaX *= scale; - } - if (deltaY) { - *deltaY *= scale; - } - } -} - -} // namespace android diff --git a/widget/gonk/libui/VelocityControl.h b/widget/gonk/libui/VelocityControl.h deleted file mode 100644 index 8a2c695d6..000000000 --- a/widget/gonk/libui/VelocityControl.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_VELOCITY_CONTROL_H -#define _ANDROIDFW_VELOCITY_CONTROL_H - -#include "Input.h" -#include "VelocityTracker.h" -#include <utils/Timers.h> - -namespace android { - -/* - * Specifies parameters that govern pointer or wheel acceleration. - */ -struct VelocityControlParameters { - // A scale factor that is multiplied with the raw velocity deltas - // prior to applying any other velocity control factors. The scale - // factor should be used to adapt the input device resolution - // (eg. counts per inch) to the output device resolution (eg. pixels per inch). - // - // Must be a positive value. - // Default is 1.0 (no scaling). - float scale; - - // The scaled speed at which acceleration begins to be applied. - // This value establishes the upper bound of a low speed regime for - // small precise motions that are performed without any acceleration. - // - // Must be a non-negative value. - // Default is 0.0 (no low threshold). - float lowThreshold; - - // The scaled speed at which maximum acceleration is applied. - // The difference between highThreshold and lowThreshold controls - // the range of speeds over which the acceleration factor is interpolated. - // The wider the range, the smoother the acceleration. - // - // Must be a non-negative value greater than or equal to lowThreshold. - // Default is 0.0 (no high threshold). - float highThreshold; - - // The acceleration factor. - // When the speed is above the low speed threshold, the velocity will scaled - // by an interpolated value between 1.0 and this amount. - // - // Must be a positive greater than or equal to 1.0. - // Default is 1.0 (no acceleration). - float acceleration; - - VelocityControlParameters() : - scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { - } - - VelocityControlParameters(float scale, float lowThreshold, - float highThreshold, float acceleration) : - scale(scale), lowThreshold(lowThreshold), - highThreshold(highThreshold), acceleration(acceleration) { - } -}; - -/* - * Implements mouse pointer and wheel speed control and acceleration. - */ -class VelocityControl { -public: - VelocityControl(); - - /* Sets the various parameters. */ - void setParameters(const VelocityControlParameters& parameters); - - /* Resets the current movement counters to zero. - * This has the effect of nullifying any acceleration. */ - void reset(); - - /* Translates a raw movement delta into an appropriately - * scaled / accelerated delta based on the current velocity. */ - void move(nsecs_t eventTime, float* deltaX, float* deltaY); - -private: - // If no movements are received within this amount of time, - // we assume the movement has stopped and reset the movement counters. - static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms - - VelocityControlParameters mParameters; - - nsecs_t mLastMovementTime; - VelocityTracker::Position mRawPosition; - VelocityTracker mVelocityTracker; -}; - -} // namespace android - -#endif // _ANDROIDFW_VELOCITY_CONTROL_H diff --git a/widget/gonk/libui/VelocityTracker.cpp b/widget/gonk/libui/VelocityTracker.cpp deleted file mode 100644 index 11a8bf7fc..000000000 --- a/widget/gonk/libui/VelocityTracker.cpp +++ /dev/null @@ -1,929 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "VelocityTracker" -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -// Log debug messages about velocity tracking. -#define DEBUG_VELOCITY 0 - -// Log debug messages about the progress of the algorithm itself. -#define DEBUG_STRATEGY 0 - -#include <math.h> -#include <limits.h> - -#include "VelocityTracker.h" -#include <utils/BitSet.h> -#include <utils/String8.h> -#include <utils/Timers.h> - -#include <cutils/properties.h> - -namespace android { - -// Nanoseconds per milliseconds. -static const nsecs_t NANOS_PER_MS = 1000000; - -// Threshold for determining that a pointer has stopped moving. -// Some input devices do not send ACTION_MOVE events in the case where a pointer has -// stopped. We need to detect this case so that we can accurately predict the -// velocity after the pointer starts moving again. -static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; - - -static float vectorDot(const float* a, const float* b, uint32_t m) { - float r = 0; - while (m--) { - r += *(a++) * *(b++); - } - return r; -} - -static float vectorNorm(const float* a, uint32_t m) { - float r = 0; - while (m--) { - float t = *(a++); - r += t * t; - } - return sqrtf(r); -} - -#if DEBUG_STRATEGY || DEBUG_VELOCITY -static String8 vectorToString(const float* a, uint32_t m) { - String8 str; - str.append("["); - while (m--) { - str.appendFormat(" %f", *(a++)); - if (m) { - str.append(","); - } - } - str.append(" ]"); - return str; -} - -static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { - String8 str; - str.append("["); - for (size_t i = 0; i < m; i++) { - if (i) { - str.append(","); - } - str.append(" ["); - for (size_t j = 0; j < n; j++) { - if (j) { - str.append(","); - } - str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]); - } - str.append(" ]"); - } - str.append(" ]"); - return str; -} -#endif - - -// --- VelocityTracker --- - -// The default velocity tracker strategy. -// Although other strategies are available for testing and comparison purposes, -// this is the strategy that applications will actually use. Be very careful -// when adjusting the default strategy because it can dramatically affect -// (often in a bad way) the user experience. -const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2"; - -VelocityTracker::VelocityTracker(const char* strategy) : - mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) { - char value[PROPERTY_VALUE_MAX]; - - // Allow the default strategy to be overridden using a system property for debugging. - if (!strategy) { - int length = property_get("debug.velocitytracker.strategy", value, NULL); - if (length > 0) { - strategy = value; - } else { - strategy = DEFAULT_STRATEGY; - } - } - - // Configure the strategy. - if (!configureStrategy(strategy)) { - ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy); - if (!configureStrategy(DEFAULT_STRATEGY)) { - LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!", - strategy); - } - } -} - -VelocityTracker::~VelocityTracker() { - delete mStrategy; -} - -bool VelocityTracker::configureStrategy(const char* strategy) { - mStrategy = createStrategy(strategy); - return mStrategy != NULL; -} - -VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { - if (!strcmp("lsq1", strategy)) { - // 1st order least squares. Quality: POOR. - // Frequently underfits the touch data especially when the finger accelerates - // or changes direction. Often underestimates velocity. The direction - // is overly influenced by historical touch points. - return new LeastSquaresVelocityTrackerStrategy(1); - } - if (!strcmp("lsq2", strategy)) { - // 2nd order least squares. Quality: VERY GOOD. - // Pretty much ideal, but can be confused by certain kinds of touch data, - // particularly if the panel has a tendency to generate delayed, - // duplicate or jittery touch coordinates when the finger is released. - return new LeastSquaresVelocityTrackerStrategy(2); - } - if (!strcmp("lsq3", strategy)) { - // 3rd order least squares. Quality: UNUSABLE. - // Frequently overfits the touch data yielding wildly divergent estimates - // of the velocity when the finger is released. - return new LeastSquaresVelocityTrackerStrategy(3); - } - if (!strcmp("wlsq2-delta", strategy)) { - // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL - return new LeastSquaresVelocityTrackerStrategy(2, - LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA); - } - if (!strcmp("wlsq2-central", strategy)) { - // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL - return new LeastSquaresVelocityTrackerStrategy(2, - LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL); - } - if (!strcmp("wlsq2-recent", strategy)) { - // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL - return new LeastSquaresVelocityTrackerStrategy(2, - LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT); - } - if (!strcmp("int1", strategy)) { - // 1st order integrating filter. Quality: GOOD. - // Not as good as 'lsq2' because it cannot estimate acceleration but it is - // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate - // the velocity of a fling but this strategy tends to respond to changes in - // direction more quickly and accurately. - return new IntegratingVelocityTrackerStrategy(1); - } - if (!strcmp("int2", strategy)) { - // 2nd order integrating filter. Quality: EXPERIMENTAL. - // For comparison purposes only. Unlike 'int1' this strategy can compensate - // for acceleration but it typically overestimates the effect. - return new IntegratingVelocityTrackerStrategy(2); - } - if (!strcmp("legacy", strategy)) { - // Legacy velocity tracker algorithm. Quality: POOR. - // For comparison purposes only. This algorithm is strongly influenced by - // old data points, consistently underestimates velocity and takes a very long - // time to adjust to changes in direction. - return new LegacyVelocityTrackerStrategy(); - } - return NULL; -} - -void VelocityTracker::clear() { - mCurrentPointerIdBits.clear(); - mActivePointerId = -1; - - mStrategy->clear(); -} - -void VelocityTracker::clearPointers(BitSet32 idBits) { - BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value); - mCurrentPointerIdBits = remainingIdBits; - - if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) { - mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; - } - - mStrategy->clearPointers(idBits); -} - -void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) { - while (idBits.count() > MAX_POINTERS) { - idBits.clearLastMarkedBit(); - } - - if ((mCurrentPointerIdBits.value & idBits.value) - && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) { -#if DEBUG_VELOCITY - ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.", - (eventTime - mLastEventTime) * 0.000001f); -#endif - // We have not received any movements for too long. Assume that all pointers - // have stopped. - mStrategy->clear(); - } - mLastEventTime = eventTime; - - mCurrentPointerIdBits = idBits; - if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) { - mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit(); - } - - mStrategy->addMovement(eventTime, idBits, positions); - -#if DEBUG_VELOCITY - ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", - eventTime, idBits.value, mActivePointerId); - for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { - uint32_t id = iterBits.firstMarkedBit(); - uint32_t index = idBits.getIndexOfBit(id); - iterBits.clearBit(id); - Estimator estimator; - getEstimator(id, &estimator); - ALOGD(" %d: position (%0.3f, %0.3f), " - "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", - id, positions[index].x, positions[index].y, - int(estimator.degree), - vectorToString(estimator.xCoeff, estimator.degree + 1).string(), - vectorToString(estimator.yCoeff, estimator.degree + 1).string(), - estimator.confidence); - } -#endif -} - -void VelocityTracker::addMovement(const MotionEvent* event) { - int32_t actionMasked = event->getActionMasked(); - - switch (actionMasked) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - // Clear all pointers on down before adding the new movement. - clear(); - break; - case AMOTION_EVENT_ACTION_POINTER_DOWN: { - // Start a new movement trace for a pointer that just went down. - // We do this on down instead of on up because the client may want to query the - // final velocity for a pointer that just went up. - BitSet32 downIdBits; - downIdBits.markBit(event->getPointerId(event->getActionIndex())); - clearPointers(downIdBits); - break; - } - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - break; - default: - // Ignore all other actions because they do not convey any new information about - // pointer movement. We also want to preserve the last known velocity of the pointers. - // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position - // of the pointers that went up. ACTION_POINTER_UP does include the new position of - // pointers that remained down but we will also receive an ACTION_MOVE with this - // information if any of them actually moved. Since we don't know how many pointers - // will be going up at once it makes sense to just wait for the following ACTION_MOVE - // before adding the movement. - return; - } - - size_t pointerCount = event->getPointerCount(); - if (pointerCount > MAX_POINTERS) { - pointerCount = MAX_POINTERS; - } - - BitSet32 idBits; - for (size_t i = 0; i < pointerCount; i++) { - idBits.markBit(event->getPointerId(i)); - } - - uint32_t pointerIndex[MAX_POINTERS]; - for (size_t i = 0; i < pointerCount; i++) { - pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i)); - } - - nsecs_t eventTime; - Position positions[pointerCount]; - - size_t historySize = event->getHistorySize(); - for (size_t h = 0; h < historySize; h++) { - eventTime = event->getHistoricalEventTime(h); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t index = pointerIndex[i]; - positions[index].x = event->getHistoricalX(i, h); - positions[index].y = event->getHistoricalY(i, h); - } - addMovement(eventTime, idBits, positions); - } - - eventTime = event->getEventTime(); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t index = pointerIndex[i]; - positions[index].x = event->getX(i); - positions[index].y = event->getY(i); - } - addMovement(eventTime, idBits, positions); -} - -bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { - Estimator estimator; - if (getEstimator(id, &estimator) && estimator.degree >= 1) { - *outVx = estimator.xCoeff[1]; - *outVy = estimator.yCoeff[1]; - return true; - } - *outVx = 0; - *outVy = 0; - return false; -} - -bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { - return mStrategy->getEstimator(id, outEstimator); -} - - -// --- LeastSquaresVelocityTrackerStrategy --- - -const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; -const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; - -LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( - uint32_t degree, Weighting weighting) : - mDegree(degree), mWeighting(weighting) { - clear(); -} - -LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { -} - -void LeastSquaresVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - -void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { - BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); - mMovements[mIndex].idBits = remainingIdBits; -} - -void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) { - if (++mIndex == HISTORY_SIZE) { - mIndex = 0; - } - - Movement& movement = mMovements[mIndex]; - movement.eventTime = eventTime; - movement.idBits = idBits; - uint32_t count = idBits.count(); - for (uint32_t i = 0; i < count; i++) { - movement.positions[i] = positions[i]; - } -} - -/** - * Solves a linear least squares problem to obtain a N degree polynomial that fits - * the specified input data as nearly as possible. - * - * Returns true if a solution is found, false otherwise. - * - * The input consists of two vectors of data points X and Y with indices 0..m-1 - * along with a weight vector W of the same size. - * - * The output is a vector B with indices 0..n that describes a polynomial - * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i] - * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized. - * - * Accordingly, the weight vector W should be initialized by the caller with the - * reciprocal square root of the variance of the error in each input data point. - * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]). - * The weights express the relative importance of each data point. If the weights are - * all 1, then the data points are considered to be of equal importance when fitting - * the polynomial. It is a good idea to choose weights that diminish the importance - * of data points that may have higher than usual error margins. - * - * Errors among data points are assumed to be independent. W is represented here - * as a vector although in the literature it is typically taken to be a diagonal matrix. - * - * That is to say, the function that generated the input data can be approximated - * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. - * - * The coefficient of determination (R^2) is also returned to describe the goodness - * of fit of the model for the given data. It is a value between 0 and 1, where 1 - * indicates perfect correspondence. - * - * This function first expands the X vector to a m by n matrix A such that - * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then - * multiplies it by w[i]./ - * - * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q - * and an m by n upper triangular matrix R. Because R is upper triangular (lower - * part is all zeroes), we can simplify the decomposition into an m by n matrix - * Q1 and a n by n matrix R1 such that A = Q1 R1. - * - * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y) - * to find B. - * - * For efficiency, we lay out A and Q column-wise in memory because we frequently - * operate on the column vectors. Conversely, we lay out R row-wise. - * - * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares - * http://en.wikipedia.org/wiki/Gram-Schmidt - */ -static bool solveLeastSquares(const float* x, const float* y, - const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { -#if DEBUG_STRATEGY - ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), - vectorToString(x, m).string(), vectorToString(y, m).string(), - vectorToString(w, m).string()); -#endif - - // Expand the X vector to a matrix A, pre-multiplied by the weights. - float a[n][m]; // column-major order - for (uint32_t h = 0; h < m; h++) { - a[0][h] = w[h]; - for (uint32_t i = 1; i < n; i++) { - a[i][h] = a[i - 1][h] * x[h]; - } - } -#if DEBUG_STRATEGY - ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string()); -#endif - - // Apply the Gram-Schmidt process to A to obtain its QR decomposition. - float q[n][m]; // orthonormal basis, column-major order - float r[n][n]; // upper triangular matrix, row-major order - for (uint32_t j = 0; j < n; j++) { - for (uint32_t h = 0; h < m; h++) { - q[j][h] = a[j][h]; - } - for (uint32_t i = 0; i < j; i++) { - float dot = vectorDot(&q[j][0], &q[i][0], m); - for (uint32_t h = 0; h < m; h++) { - q[j][h] -= dot * q[i][h]; - } - } - - float norm = vectorNorm(&q[j][0], m); - if (norm < 0.000001f) { - // vectors are linearly dependent or zero so no solution -#if DEBUG_STRATEGY - ALOGD(" - no solution, norm=%f", norm); -#endif - return false; - } - - float invNorm = 1.0f / norm; - for (uint32_t h = 0; h < m; h++) { - q[j][h] *= invNorm; - } - for (uint32_t i = 0; i < n; i++) { - r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m); - } - } -#if DEBUG_STRATEGY - ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string()); - ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string()); - - // calculate QR, if we factored A correctly then QR should equal A - float qr[n][m]; - for (uint32_t h = 0; h < m; h++) { - for (uint32_t i = 0; i < n; i++) { - qr[i][h] = 0; - for (uint32_t j = 0; j < n; j++) { - qr[i][h] += q[j][h] * r[j][i]; - } - } - } - ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); -#endif - - // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. - // We just work from bottom-right to top-left calculating B's coefficients. - float wy[m]; - for (uint32_t h = 0; h < m; h++) { - wy[h] = y[h] * w[h]; - } - for (uint32_t i = n; i-- != 0; ) { - outB[i] = vectorDot(&q[i][0], wy, m); - for (uint32_t j = n - 1; j > i; j--) { - outB[i] -= r[i][j] * outB[j]; - } - outB[i] /= r[i][i]; - } -#if DEBUG_STRATEGY - ALOGD(" - b=%s", vectorToString(outB, n).string()); -#endif - - // Calculate the coefficient of determination as 1 - (SSerr / SStot) where - // SSerr is the residual sum of squares (variance of the error), - // and SStot is the total sum of squares (variance of the data) where each - // has been weighted. - float ymean = 0; - for (uint32_t h = 0; h < m; h++) { - ymean += y[h]; - } - ymean /= m; - - float sserr = 0; - float sstot = 0; - for (uint32_t h = 0; h < m; h++) { - float err = y[h] - outB[0]; - float term = 1; - for (uint32_t i = 1; i < n; i++) { - term *= x[h]; - err -= term * outB[i]; - } - sserr += w[h] * w[h] * err * err; - float var = y[h] - ymean; - sstot += w[h] * w[h] * var * var; - } - *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; -#if DEBUG_STRATEGY - ALOGD(" - sserr=%f", sserr); - ALOGD(" - sstot=%f", sstot); - ALOGD(" - det=%f", *outDet); -#endif - return true; -} - -bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->clear(); - - // Iterate over movement samples in reverse time order and collect samples. - float x[HISTORY_SIZE]; - float y[HISTORY_SIZE]; - float w[HISTORY_SIZE]; - float time[HISTORY_SIZE]; - uint32_t m = 0; - uint32_t index = mIndex; - const Movement& newestMovement = mMovements[mIndex]; - do { - const Movement& movement = mMovements[index]; - if (!movement.idBits.hasBit(id)) { - break; - } - - nsecs_t age = newestMovement.eventTime - movement.eventTime; - if (age > HORIZON) { - break; - } - - const VelocityTracker::Position& position = movement.getPosition(id); - x[m] = position.x; - y[m] = position.y; - w[m] = chooseWeight(index); - time[m] = -age * 0.000000001f; - index = (index == 0 ? HISTORY_SIZE : index) - 1; - } while (++m < HISTORY_SIZE); - - if (m == 0) { - return false; // no data - } - - // Calculate a least squares polynomial fit. - uint32_t degree = mDegree; - if (degree > m - 1) { - degree = m - 1; - } - if (degree >= 1) { - float xdet, ydet; - uint32_t n = degree + 1; - if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet) - && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) { - outEstimator->time = newestMovement.eventTime; - outEstimator->degree = degree; - outEstimator->confidence = xdet * ydet; -#if DEBUG_STRATEGY - ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", - int(outEstimator->degree), - vectorToString(outEstimator->xCoeff, n).string(), - vectorToString(outEstimator->yCoeff, n).string(), - outEstimator->confidence); -#endif - return true; - } - } - - // No velocity data available for this pointer, but we do have its current position. - outEstimator->xCoeff[0] = x[0]; - outEstimator->yCoeff[0] = y[0]; - outEstimator->time = newestMovement.eventTime; - outEstimator->degree = 0; - outEstimator->confidence = 1; - return true; -} - -float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const { - switch (mWeighting) { - case WEIGHTING_DELTA: { - // Weight points based on how much time elapsed between them and the next - // point so that points that "cover" a shorter time span are weighed less. - // delta 0ms: 0.5 - // delta 10ms: 1.0 - if (index == mIndex) { - return 1.0f; - } - uint32_t nextIndex = (index + 1) % HISTORY_SIZE; - float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime) - * 0.000001f; - if (deltaMillis < 0) { - return 0.5f; - } - if (deltaMillis < 10) { - return 0.5f + deltaMillis * 0.05; - } - return 1.0f; - } - - case WEIGHTING_CENTRAL: { - // Weight points based on their age, weighing very recent and very old points less. - // age 0ms: 0.5 - // age 10ms: 1.0 - // age 50ms: 1.0 - // age 60ms: 0.5 - float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) - * 0.000001f; - if (ageMillis < 0) { - return 0.5f; - } - if (ageMillis < 10) { - return 0.5f + ageMillis * 0.05; - } - if (ageMillis < 50) { - return 1.0f; - } - if (ageMillis < 60) { - return 0.5f + (60 - ageMillis) * 0.05; - } - return 0.5f; - } - - case WEIGHTING_RECENT: { - // Weight points based on their age, weighing older points less. - // age 0ms: 1.0 - // age 50ms: 1.0 - // age 100ms: 0.5 - float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) - * 0.000001f; - if (ageMillis < 50) { - return 1.0f; - } - if (ageMillis < 100) { - return 0.5f + (100 - ageMillis) * 0.01f; - } - return 0.5f; - } - - case WEIGHTING_NONE: - default: - return 1.0f; - } -} - - -// --- IntegratingVelocityTrackerStrategy --- - -IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) : - mDegree(degree) { -} - -IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() { -} - -void IntegratingVelocityTrackerStrategy::clear() { - mPointerIdBits.clear(); -} - -void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { - mPointerIdBits.value &= ~idBits.value; -} - -void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) { - uint32_t index = 0; - for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) { - uint32_t id = iterIdBits.clearFirstMarkedBit(); - State& state = mPointerState[id]; - const VelocityTracker::Position& position = positions[index++]; - if (mPointerIdBits.hasBit(id)) { - updateState(state, eventTime, position.x, position.y); - } else { - initState(state, eventTime, position.x, position.y); - } - } - - mPointerIdBits = idBits; -} - -bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->clear(); - - if (mPointerIdBits.hasBit(id)) { - const State& state = mPointerState[id]; - populateEstimator(state, outEstimator); - return true; - } - - return false; -} - -void IntegratingVelocityTrackerStrategy::initState(State& state, - nsecs_t eventTime, float xpos, float ypos) const { - state.updateTime = eventTime; - state.degree = 0; - - state.xpos = xpos; - state.xvel = 0; - state.xaccel = 0; - state.ypos = ypos; - state.yvel = 0; - state.yaccel = 0; -} - -void IntegratingVelocityTrackerStrategy::updateState(State& state, - nsecs_t eventTime, float xpos, float ypos) const { - const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS; - const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds - - if (eventTime <= state.updateTime + MIN_TIME_DELTA) { - return; - } - - float dt = (eventTime - state.updateTime) * 0.000000001f; - state.updateTime = eventTime; - - float xvel = (xpos - state.xpos) / dt; - float yvel = (ypos - state.ypos) / dt; - if (state.degree == 0) { - state.xvel = xvel; - state.yvel = yvel; - state.degree = 1; - } else { - float alpha = dt / (FILTER_TIME_CONSTANT + dt); - if (mDegree == 1) { - state.xvel += (xvel - state.xvel) * alpha; - state.yvel += (yvel - state.yvel) * alpha; - } else { - float xaccel = (xvel - state.xvel) / dt; - float yaccel = (yvel - state.yvel) / dt; - if (state.degree == 1) { - state.xaccel = xaccel; - state.yaccel = yaccel; - state.degree = 2; - } else { - state.xaccel += (xaccel - state.xaccel) * alpha; - state.yaccel += (yaccel - state.yaccel) * alpha; - } - state.xvel += (state.xaccel * dt) * alpha; - state.yvel += (state.yaccel * dt) * alpha; - } - } - state.xpos = xpos; - state.ypos = ypos; -} - -void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->time = state.updateTime; - outEstimator->confidence = 1.0f; - outEstimator->degree = state.degree; - outEstimator->xCoeff[0] = state.xpos; - outEstimator->xCoeff[1] = state.xvel; - outEstimator->xCoeff[2] = state.xaccel / 2; - outEstimator->yCoeff[0] = state.ypos; - outEstimator->yCoeff[1] = state.yvel; - outEstimator->yCoeff[2] = state.yaccel / 2; -} - - -// --- LegacyVelocityTrackerStrategy --- - -const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; -const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; -const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; - -LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { - clear(); -} - -LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { -} - -void LegacyVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - -void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { - BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); - mMovements[mIndex].idBits = remainingIdBits; -} - -void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) { - if (++mIndex == HISTORY_SIZE) { - mIndex = 0; - } - - Movement& movement = mMovements[mIndex]; - movement.eventTime = eventTime; - movement.idBits = idBits; - uint32_t count = idBits.count(); - for (uint32_t i = 0; i < count; i++) { - movement.positions[i] = positions[i]; - } -} - -bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->clear(); - - const Movement& newestMovement = mMovements[mIndex]; - if (!newestMovement.idBits.hasBit(id)) { - return false; // no data - } - - // Find the oldest sample that contains the pointer and that is not older than HORIZON. - nsecs_t minTime = newestMovement.eventTime - HORIZON; - uint32_t oldestIndex = mIndex; - uint32_t numTouches = 1; - do { - uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; - const Movement& nextOldestMovement = mMovements[nextOldestIndex]; - if (!nextOldestMovement.idBits.hasBit(id) - || nextOldestMovement.eventTime < minTime) { - break; - } - oldestIndex = nextOldestIndex; - } while (++numTouches < HISTORY_SIZE); - - // Calculate an exponentially weighted moving average of the velocity estimate - // at different points in time measured relative to the oldest sample. - // This is essentially an IIR filter. Newer samples are weighted more heavily - // than older samples. Samples at equal time points are weighted more or less - // equally. - // - // One tricky problem is that the sample data may be poorly conditioned. - // Sometimes samples arrive very close together in time which can cause us to - // overestimate the velocity at that time point. Most samples might be measured - // 16ms apart but some consecutive samples could be only 0.5sm apart because - // the hardware or driver reports them irregularly or in bursts. - float accumVx = 0; - float accumVy = 0; - uint32_t index = oldestIndex; - uint32_t samplesUsed = 0; - const Movement& oldestMovement = mMovements[oldestIndex]; - const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id); - nsecs_t lastDuration = 0; - - while (numTouches-- > 1) { - if (++index == HISTORY_SIZE) { - index = 0; - } - const Movement& movement = mMovements[index]; - nsecs_t duration = movement.eventTime - oldestMovement.eventTime; - - // If the duration between samples is small, we may significantly overestimate - // the velocity. Consequently, we impose a minimum duration constraint on the - // samples that we include in the calculation. - if (duration >= MIN_DURATION) { - const VelocityTracker::Position& position = movement.getPosition(id); - float scale = 1000000000.0f / duration; // one over time delta in seconds - float vx = (position.x - oldestPosition.x) * scale; - float vy = (position.y - oldestPosition.y) * scale; - accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); - accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); - lastDuration = duration; - samplesUsed += 1; - } - } - - // Report velocity. - const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id); - outEstimator->time = newestMovement.eventTime; - outEstimator->confidence = 1; - outEstimator->xCoeff[0] = newestPosition.x; - outEstimator->yCoeff[0] = newestPosition.y; - if (samplesUsed) { - outEstimator->xCoeff[1] = accumVx; - outEstimator->yCoeff[1] = accumVy; - outEstimator->degree = 1; - } else { - outEstimator->degree = 0; - } - return true; -} - -} // namespace android diff --git a/widget/gonk/libui/VelocityTracker.h b/widget/gonk/libui/VelocityTracker.h deleted file mode 100644 index fd077d438..000000000 --- a/widget/gonk/libui/VelocityTracker.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_VELOCITY_TRACKER_H -#define _ANDROIDFW_VELOCITY_TRACKER_H - -#include "Input.h" -#include <utils/Timers.h> -#include <utils/BitSet.h> - -namespace android { - -class VelocityTrackerStrategy; - -/* - * Calculates the velocity of pointer movements over time. - */ -class VelocityTracker { -public: - struct Position { - float x, y; - }; - - struct Estimator { - static const size_t MAX_DEGREE = 4; - - // Estimator time base. - nsecs_t time; - - // Polynomial coefficients describing motion in X and Y. - float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; - - // Polynomial degree (number of coefficients), or zero if no information is - // available. - uint32_t degree; - - // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). - float confidence; - - inline void clear() { - time = 0; - degree = 0; - confidence = 0; - for (size_t i = 0; i <= MAX_DEGREE; i++) { - xCoeff[i] = 0; - yCoeff[i] = 0; - } - } - }; - - // Creates a velocity tracker using the specified strategy. - // If strategy is NULL, uses the default strategy for the platform. - VelocityTracker(const char* strategy = NULL); - - ~VelocityTracker(); - - // Resets the velocity tracker state. - void clear(); - - // Resets the velocity tracker state for specific pointers. - // Call this method when some pointers have changed and may be reusing - // an id that was assigned to a different pointer earlier. - void clearPointers(BitSet32 idBits); - - // Adds movement information for a set of pointers. - // The idBits bitfield specifies the pointer ids of the pointers whose positions - // are included in the movement. - // The positions array contains position information for each pointer in order by - // increasing id. Its size should be equal to the number of one bits in idBits. - void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions); - - // Adds movement information for all pointers in a MotionEvent, including historical samples. - void addMovement(const MotionEvent* event); - - // Gets the velocity of the specified pointer id in position units per second. - // Returns false and sets the velocity components to zero if there is - // insufficient movement information for the pointer. - bool getVelocity(uint32_t id, float* outVx, float* outVy) const; - - // Gets an estimator for the recent movements of the specified pointer id. - // Returns false and clears the estimator if there is no information available - // about the pointer. - bool getEstimator(uint32_t id, Estimator* outEstimator) const; - - // Gets the active pointer id, or -1 if none. - inline int32_t getActivePointerId() const { return mActivePointerId; } - - // Gets a bitset containing all pointer ids from the most recent movement. - inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } - -private: - static const char* DEFAULT_STRATEGY; - - nsecs_t mLastEventTime; - BitSet32 mCurrentPointerIdBits; - int32_t mActivePointerId; - VelocityTrackerStrategy* mStrategy; - - bool configureStrategy(const char* strategy); - - static VelocityTrackerStrategy* createStrategy(const char* strategy); -}; - - -/* - * Implements a particular velocity tracker algorithm. - */ -class VelocityTrackerStrategy { -protected: - VelocityTrackerStrategy() { } - -public: - virtual ~VelocityTrackerStrategy() { } - - virtual void clear() = 0; - virtual void clearPointers(BitSet32 idBits) = 0; - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) = 0; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; -}; - - -/* - * Velocity tracker algorithm based on least-squares linear regression. - */ -class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { -public: - enum Weighting { - // No weights applied. All data points are equally reliable. - WEIGHTING_NONE, - - // Weight by time delta. Data points clustered together are weighted less. - WEIGHTING_DELTA, - - // Weight such that points within a certain horizon are weighed more than those - // outside of that horizon. - WEIGHTING_CENTRAL, - - // Weight such that points older than a certain amount are weighed less. - WEIGHTING_RECENT, - }; - - // Degree must be no greater than Estimator::MAX_DEGREE. - LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); - virtual ~LeastSquaresVelocityTrackerStrategy(); - - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions); - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; - -private: - // Sample horizon. - // We don't use too much history by default since we want to react to quick - // changes in direction. - static const nsecs_t HORIZON = 100 * 1000000; // 100 ms - - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } - }; - - float chooseWeight(uint32_t index) const; - - const uint32_t mDegree; - const Weighting mWeighting; - uint32_t mIndex; - Movement mMovements[HISTORY_SIZE]; -}; - - -/* - * Velocity tracker algorithm that uses an IIR filter. - */ -class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { -public: - // Degree must be 1 or 2. - IntegratingVelocityTrackerStrategy(uint32_t degree); - ~IntegratingVelocityTrackerStrategy(); - - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions); - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; - -private: - // Current state estimate for a particular pointer. - struct State { - nsecs_t updateTime; - uint32_t degree; - - float xpos, xvel, xaccel; - float ypos, yvel, yaccel; - }; - - const uint32_t mDegree; - BitSet32 mPointerIdBits; - State mPointerState[MAX_POINTER_ID + 1]; - - void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; - void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; - void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; -}; - - -/* - * Velocity tracker strategy used prior to ICS. - */ -class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { -public: - LegacyVelocityTrackerStrategy(); - virtual ~LegacyVelocityTrackerStrategy(); - - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions); - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; - -private: - // Oldest sample to consider when calculating the velocity. - static const nsecs_t HORIZON = 200 * 1000000; // 100 ms - - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - // The minimum duration between samples when estimating velocity. - static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms - - struct Movement { - nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } - }; - - uint32_t mIndex; - Movement mMovements[HISTORY_SIZE]; -}; - -} // namespace android - -#endif // _ANDROIDFW_VELOCITY_TRACKER_H diff --git a/widget/gonk/libui/VirtualKeyMap.cpp b/widget/gonk/libui/VirtualKeyMap.cpp deleted file mode 100644 index 444ab3718..000000000 --- a/widget/gonk/libui/VirtualKeyMap.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#define LOG_TAG "VirtualKeyMap" -#include "cutils_log.h" - -#include <stdlib.h> -#include <string.h> -#include "VirtualKeyMap.h" -#include <utils/Errors.h> -#include "Tokenizer.h" -#include <utils/Timers.h> - -// Enables debug output for the parser. -#define DEBUG_PARSER 0 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; -static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; - - -// --- VirtualKeyMap --- - -VirtualKeyMap::VirtualKeyMap() { -} - -VirtualKeyMap::~VirtualKeyMap() { -} - -status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) { - *outMap = NULL; - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening virtual key map file %s.", status, filename.string()); - } else { - VirtualKeyMap* map = new VirtualKeyMap(); - if (!map) { - ALOGE("Error allocating virtual key map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map, tokenizer); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (status) { - delete map; - } else { - *outMap = map; - } - } - delete tokenizer; - } - return status; -} - - -// --- VirtualKeyMap::Parser --- - -VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : - mMap(map), mTokenizer(tokenizer) { -} - -VirtualKeyMap::Parser::~Parser() { -} - -status_t VirtualKeyMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - // Multiple keys can appear on one line or they can be broken up across multiple lines. - do { - String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); - if (token != "0x01") { - ALOGE("%s: Unknown virtual key type, expected 0x01.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - VirtualKeyDefinition defn; - bool success = parseNextIntField(&defn.scanCode) - && parseNextIntField(&defn.centerX) - && parseNextIntField(&defn.centerY) - && parseNextIntField(&defn.width) - && parseNextIntField(&defn.height); - if (!success) { - ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, " - "width=%d, height=%d", - defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height); -#endif - mMap->mVirtualKeys.push(defn); - } while (consumeFieldDelimiterAndSkipWhitespace()); - - if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - } - - mTokenizer->nextLine(); - } - - return NO_ERROR; -} - -bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() { - mTokenizer->skipDelimiters(WHITESPACE); - if (mTokenizer->peekChar() == ':') { - mTokenizer->nextChar(); - mTokenizer->skipDelimiters(WHITESPACE); - return true; - } - return false; -} - -bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { - if (!consumeFieldDelimiterAndSkipWhitespace()) { - return false; - } - - String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); - char* end; - *outValue = strtol(token.string(), &end, 0); - if (token.isEmpty() || *end != '\0') { - ALOGE("Expected an integer, got '%s'.", token.string()); - return false; - } - return true; -} - -} // namespace android diff --git a/widget/gonk/libui/VirtualKeyMap.h b/widget/gonk/libui/VirtualKeyMap.h deleted file mode 100644 index 79d61a536..000000000 --- a/widget/gonk/libui/VirtualKeyMap.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROIDFW_VIRTUAL_KEY_MAP_H -#define _ANDROIDFW_VIRTUAL_KEY_MAP_H - -#include <stdint.h> - -#include "Input.h" -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include "Tokenizer.h" -#include <utils/String8.h> -#include <utils/Unicode.h> - -namespace android { - -/* Describes a virtual key. */ -struct VirtualKeyDefinition { - int32_t scanCode; - - // configured position data, specified in display coords - int32_t centerX; - int32_t centerY; - int32_t width; - int32_t height; -}; - - -/** - * Describes a collection of virtual keys on a touch screen in terms of - * virtual scan codes and hit rectangles. - * - * This object is immutable after it has been loaded. - */ -class VirtualKeyMap { -public: - ~VirtualKeyMap(); - - static status_t load(const String8& filename, VirtualKeyMap** outMap); - - inline const Vector<VirtualKeyDefinition>& getVirtualKeys() const { - return mVirtualKeys; - } - -private: - class Parser { - VirtualKeyMap* mMap; - Tokenizer* mTokenizer; - - public: - Parser(VirtualKeyMap* map, Tokenizer* tokenizer); - ~Parser(); - status_t parse(); - - private: - bool consumeFieldDelimiterAndSkipWhitespace(); - bool parseNextIntField(int32_t* outValue); - }; - - Vector<VirtualKeyDefinition> mVirtualKeys; - - VirtualKeyMap(); -}; - -} // namespace android - -#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H diff --git a/widget/gonk/libui/android_input.h b/widget/gonk/libui/android_input.h deleted file mode 100644 index 00e81b28d..000000000 --- a/widget/gonk/libui/android_input.h +++ /dev/null @@ -1,850 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROID_INPUT_H -#define _ANDROID_INPUT_H - -/****************************************************************** - * - * IMPORTANT NOTICE: - * - * This file is part of Android's set of stable system headers - * exposed by the Android NDK (Native Development Kit). - * - * Third-party source AND binary code relies on the definitions - * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. - * - * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) - * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS - * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY - * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES - */ - -/* - * Structures and functions to receive and process input events in - * native code. - * - * NOTE: These functions MUST be implemented by /system/lib/libui.so - */ - -#include <stdint.h> -#include <sys/types.h> -#include "android_keycodes.h" -#include <android/looper.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Key states (may be returned by queries about the current state of a - * particular key code, scan code or switch). - */ -enum { - /* The key state is unknown or the requested key itself is not supported. */ - AKEY_STATE_UNKNOWN = -1, - - /* The key is up. */ - AKEY_STATE_UP = 0, - - /* The key is down. */ - AKEY_STATE_DOWN = 1, - - /* The key is down but is a virtual key press that is being emulated by the system. */ - AKEY_STATE_VIRTUAL = 2 -}; - -/* - * Meta key / modifer state. - */ -enum { - /* No meta keys are pressed. */ - AMETA_NONE = 0, - - /* This mask is used to check whether one of the ALT meta keys is pressed. */ - AMETA_ALT_ON = 0x02, - - /* This mask is used to check whether the left ALT meta key is pressed. */ - AMETA_ALT_LEFT_ON = 0x10, - - /* This mask is used to check whether the right ALT meta key is pressed. */ - AMETA_ALT_RIGHT_ON = 0x20, - - /* This mask is used to check whether one of the SHIFT meta keys is pressed. */ - AMETA_SHIFT_ON = 0x01, - - /* This mask is used to check whether the left SHIFT meta key is pressed. */ - AMETA_SHIFT_LEFT_ON = 0x40, - - /* This mask is used to check whether the right SHIFT meta key is pressed. */ - AMETA_SHIFT_RIGHT_ON = 0x80, - - /* This mask is used to check whether the SYM meta key is pressed. */ - AMETA_SYM_ON = 0x04, - - /* This mask is used to check whether the FUNCTION meta key is pressed. */ - AMETA_FUNCTION_ON = 0x08, - - /* This mask is used to check whether one of the CTRL meta keys is pressed. */ - AMETA_CTRL_ON = 0x1000, - - /* This mask is used to check whether the left CTRL meta key is pressed. */ - AMETA_CTRL_LEFT_ON = 0x2000, - - /* This mask is used to check whether the right CTRL meta key is pressed. */ - AMETA_CTRL_RIGHT_ON = 0x4000, - - /* This mask is used to check whether one of the META meta keys is pressed. */ - AMETA_META_ON = 0x10000, - - /* This mask is used to check whether the left META meta key is pressed. */ - AMETA_META_LEFT_ON = 0x20000, - - /* This mask is used to check whether the right META meta key is pressed. */ - AMETA_META_RIGHT_ON = 0x40000, - - /* This mask is used to check whether the CAPS LOCK meta key is on. */ - AMETA_CAPS_LOCK_ON = 0x100000, - - /* This mask is used to check whether the NUM LOCK meta key is on. */ - AMETA_NUM_LOCK_ON = 0x200000, - - /* This mask is used to check whether the SCROLL LOCK meta key is on. */ - AMETA_SCROLL_LOCK_ON = 0x400000, -}; - -/* - * Input events. - * - * Input events are opaque structures. Use the provided accessors functions to - * read their properties. - */ -struct AInputEvent; -typedef struct AInputEvent AInputEvent; - -/* - * Input event types. - */ -enum { - /* Indicates that the input event is a key event. */ - AINPUT_EVENT_TYPE_KEY = 1, - - /* Indicates that the input event is a motion event. */ - AINPUT_EVENT_TYPE_MOTION = 2 -}; - -/* - * Key event actions. - */ -enum { - /* The key has been pressed down. */ - AKEY_EVENT_ACTION_DOWN = 0, - - /* The key has been released. */ - AKEY_EVENT_ACTION_UP = 1, - - /* Multiple duplicate key events have occurred in a row, or a complex string is - * being delivered. The repeat_count property of the key event contains the number - * of times the given key code should be executed. - */ - AKEY_EVENT_ACTION_MULTIPLE = 2 -}; - -/* - * Key event flags. - */ -enum { - /* This mask is set if the device woke because of this key event. */ - AKEY_EVENT_FLAG_WOKE_HERE = 0x1, - - /* This mask is set if the key event was generated by a software keyboard. */ - AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2, - - /* This mask is set if we don't want the key event to cause us to leave touch mode. */ - AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4, - - /* This mask is set if an event was known to come from a trusted part - * of the system. That is, the event is known to come from the user, - * and could not have been spoofed by a third party component. */ - AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8, - - /* This mask is used for compatibility, to identify enter keys that are - * coming from an IME whose enter key has been auto-labelled "next" or - * "done". This allows TextView to dispatch these as normal enter keys - * for old applications, but still do the appropriate action when - * receiving them. */ - AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10, - - /* When associated with up key events, this indicates that the key press - * has been canceled. Typically this is used with virtual touch screen - * keys, where the user can slide from the virtual key area on to the - * display: in that case, the application will receive a canceled up - * event and should not perform the action normally associated with the - * key. Note that for this to work, the application can not perform an - * action for a key until it receives an up or the long press timeout has - * expired. */ - AKEY_EVENT_FLAG_CANCELED = 0x20, - - /* This key event was generated by a virtual (on-screen) hard key area. - * Typically this is an area of the touchscreen, outside of the regular - * display, dedicated to "hardware" buttons. */ - AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40, - - /* This flag is set for the first key repeat that occurs after the - * long press timeout. */ - AKEY_EVENT_FLAG_LONG_PRESS = 0x80, - - /* Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long - * press action was executed while it was down. */ - AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100, - - /* Set for AKEY_EVENT_ACTION_UP when this event's key code is still being - * tracked from its initial down. That is, somebody requested that tracking - * started on the key down and a long press has not caused - * the tracking to be canceled. */ - AKEY_EVENT_FLAG_TRACKING = 0x200, - - /* Set when a key event has been synthesized to implement default behavior - * for an event that the application did not handle. - * Fallback key events are generated by unhandled trackball motions - * (to emulate a directional keypad) and by certain unhandled key presses - * that are declared in the key map (such as special function numeric keypad - * keys when numlock is off). */ - AKEY_EVENT_FLAG_FALLBACK = 0x400, -}; - -/* - * Motion event actions. - */ - -/* Bit shift for the action bits holding the pointer index as - * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK. - */ -#define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8 - -enum { - /* Bit mask of the parts of the action code that are the action itself. - */ - AMOTION_EVENT_ACTION_MASK = 0xff, - - /* Bits in the action code that represent a pointer index, used with - * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting - * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer - * index where the data for the pointer going up or down can be found. - */ - AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00, - - /* A pressed gesture has started, the motion contains the initial starting location. - */ - AMOTION_EVENT_ACTION_DOWN = 0, - - /* A pressed gesture has finished, the motion contains the final release location - * as well as any intermediate points since the last down or move event. - */ - AMOTION_EVENT_ACTION_UP = 1, - - /* A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and - * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as - * any intermediate points since the last down or move event. - */ - AMOTION_EVENT_ACTION_MOVE = 2, - - /* The current gesture has been aborted. - * You will not receive any more points in it. You should treat this as - * an up event, but not perform any action that you normally would. - */ - AMOTION_EVENT_ACTION_CANCEL = 3, - - /* A movement has happened outside of the normal bounds of the UI element. - * This does not provide a full gesture, but only the initial location of the movement/touch. - */ - AMOTION_EVENT_ACTION_OUTSIDE = 4, - - /* A non-primary pointer has gone down. - * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. - */ - AMOTION_EVENT_ACTION_POINTER_DOWN = 5, - - /* A non-primary pointer has gone up. - * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. - */ - AMOTION_EVENT_ACTION_POINTER_UP = 6, - - /* A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE). - * The motion contains the most recent point, as well as any intermediate points since - * the last hover move event. - */ - AMOTION_EVENT_ACTION_HOVER_MOVE = 7, - - /* The motion event contains relative vertical and/or horizontal scroll offsets. - * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL - * and AMOTION_EVENT_AXIS_HSCROLL. - * The pointer may or may not be down when this event is dispatched. - * This action is always delivered to the winder under the pointer, which - * may not be the window currently touched. - */ - AMOTION_EVENT_ACTION_SCROLL = 8, - - /* The pointer is not down but has entered the boundaries of a window or view. - */ - AMOTION_EVENT_ACTION_HOVER_ENTER = 9, - - /* The pointer is not down but has exited the boundaries of a window or view. - */ - AMOTION_EVENT_ACTION_HOVER_EXIT = 10, -}; - -/* - * Motion event flags. - */ -enum { - /* This flag indicates that the window that received this motion event is partly - * or wholly obscured by another visible window above it. This flag is set to true - * even if the event did not directly pass through the obscured area. - * A security sensitive application can check this flag to identify situations in which - * a malicious application may have covered up part of its content for the purpose - * of misleading the user or hijacking touches. An appropriate response might be - * to drop the suspect touches or to take additional precautions to confirm the user's - * actual intent. - */ - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1, -}; - -/* - * Motion event edge touch flags. - */ -enum { - /* No edges intersected */ - AMOTION_EVENT_EDGE_FLAG_NONE = 0, - - /* Flag indicating the motion event intersected the top edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_TOP = 0x01, - - /* Flag indicating the motion event intersected the bottom edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02, - - /* Flag indicating the motion event intersected the left edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04, - - /* Flag indicating the motion event intersected the right edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08 -}; - -/* - * Constants that identify each individual axis of a motion event. - * Refer to the documentation on the MotionEvent class for descriptions of each axis. - */ -enum { - AMOTION_EVENT_AXIS_X = 0, - AMOTION_EVENT_AXIS_Y = 1, - AMOTION_EVENT_AXIS_PRESSURE = 2, - AMOTION_EVENT_AXIS_SIZE = 3, - AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4, - AMOTION_EVENT_AXIS_TOUCH_MINOR = 5, - AMOTION_EVENT_AXIS_TOOL_MAJOR = 6, - AMOTION_EVENT_AXIS_TOOL_MINOR = 7, - AMOTION_EVENT_AXIS_ORIENTATION = 8, - AMOTION_EVENT_AXIS_VSCROLL = 9, - AMOTION_EVENT_AXIS_HSCROLL = 10, - AMOTION_EVENT_AXIS_Z = 11, - AMOTION_EVENT_AXIS_RX = 12, - AMOTION_EVENT_AXIS_RY = 13, - AMOTION_EVENT_AXIS_RZ = 14, - AMOTION_EVENT_AXIS_HAT_X = 15, - AMOTION_EVENT_AXIS_HAT_Y = 16, - AMOTION_EVENT_AXIS_LTRIGGER = 17, - AMOTION_EVENT_AXIS_RTRIGGER = 18, - AMOTION_EVENT_AXIS_THROTTLE = 19, - AMOTION_EVENT_AXIS_RUDDER = 20, - AMOTION_EVENT_AXIS_WHEEL = 21, - AMOTION_EVENT_AXIS_GAS = 22, - AMOTION_EVENT_AXIS_BRAKE = 23, - AMOTION_EVENT_AXIS_DISTANCE = 24, - AMOTION_EVENT_AXIS_TILT = 25, - AMOTION_EVENT_AXIS_GENERIC_1 = 32, - AMOTION_EVENT_AXIS_GENERIC_2 = 33, - AMOTION_EVENT_AXIS_GENERIC_3 = 34, - AMOTION_EVENT_AXIS_GENERIC_4 = 35, - AMOTION_EVENT_AXIS_GENERIC_5 = 36, - AMOTION_EVENT_AXIS_GENERIC_6 = 37, - AMOTION_EVENT_AXIS_GENERIC_7 = 38, - AMOTION_EVENT_AXIS_GENERIC_8 = 39, - AMOTION_EVENT_AXIS_GENERIC_9 = 40, - AMOTION_EVENT_AXIS_GENERIC_10 = 41, - AMOTION_EVENT_AXIS_GENERIC_11 = 42, - AMOTION_EVENT_AXIS_GENERIC_12 = 43, - AMOTION_EVENT_AXIS_GENERIC_13 = 44, - AMOTION_EVENT_AXIS_GENERIC_14 = 45, - AMOTION_EVENT_AXIS_GENERIC_15 = 46, - AMOTION_EVENT_AXIS_GENERIC_16 = 47, - - // NOTE: If you add a new axis here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. -}; - -/* - * Constants that identify buttons that are associated with motion events. - * Refer to the documentation on the MotionEvent class for descriptions of each button. - */ -enum { - AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, - AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, - AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, - AMOTION_EVENT_BUTTON_BACK = 1 << 3, - AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, -}; - -/* - * Constants that identify tool types. - * Refer to the documentation on the MotionEvent class for descriptions of each tool type. - */ -enum { - AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0, - AMOTION_EVENT_TOOL_TYPE_FINGER = 1, - AMOTION_EVENT_TOOL_TYPE_STYLUS = 2, - AMOTION_EVENT_TOOL_TYPE_MOUSE = 3, - AMOTION_EVENT_TOOL_TYPE_ERASER = 4, -}; - -/* - * Input sources. - * - * Refer to the documentation on android.view.InputDevice for more details about input sources - * and their correct interpretation. - */ -enum { - AINPUT_SOURCE_CLASS_MASK = 0x000000ff, - - AINPUT_SOURCE_CLASS_NONE = 0x00000000, - AINPUT_SOURCE_CLASS_BUTTON = 0x00000001, - AINPUT_SOURCE_CLASS_POINTER = 0x00000002, - AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004, - AINPUT_SOURCE_CLASS_POSITION = 0x00000008, - AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010, -}; - -enum { - AINPUT_SOURCE_UNKNOWN = 0x00000000, - - AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON, - AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON, - AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON, - AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, - AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, - AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, - AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, - AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, - AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE, - AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, - - AINPUT_SOURCE_ANY = 0xffffff00, -}; - -/* - * Keyboard types. - * - * Refer to the documentation on android.view.InputDevice for more details. - */ -enum { - AINPUT_KEYBOARD_TYPE_NONE = 0, - AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1, - AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2, -}; - -/* - * Constants used to retrieve information about the range of motion for a particular - * coordinate of a motion event. - * - * Refer to the documentation on android.view.InputDevice for more details about input sources - * and their correct interpretation. - * - * DEPRECATION NOTICE: These constants are deprecated. Use AMOTION_EVENT_AXIS_* constants instead. - */ -enum { - AINPUT_MOTION_RANGE_X = AMOTION_EVENT_AXIS_X, - AINPUT_MOTION_RANGE_Y = AMOTION_EVENT_AXIS_Y, - AINPUT_MOTION_RANGE_PRESSURE = AMOTION_EVENT_AXIS_PRESSURE, - AINPUT_MOTION_RANGE_SIZE = AMOTION_EVENT_AXIS_SIZE, - AINPUT_MOTION_RANGE_TOUCH_MAJOR = AMOTION_EVENT_AXIS_TOUCH_MAJOR, - AINPUT_MOTION_RANGE_TOUCH_MINOR = AMOTION_EVENT_AXIS_TOUCH_MINOR, - AINPUT_MOTION_RANGE_TOOL_MAJOR = AMOTION_EVENT_AXIS_TOOL_MAJOR, - AINPUT_MOTION_RANGE_TOOL_MINOR = AMOTION_EVENT_AXIS_TOOL_MINOR, - AINPUT_MOTION_RANGE_ORIENTATION = AMOTION_EVENT_AXIS_ORIENTATION, -} __attribute__ ((deprecated)); - - -/* - * Input event accessors. - * - * Note that most functions can only be used on input events that are of a given type. - * Calling these functions on input events of other types will yield undefined behavior. - */ - -/*** Accessors for all input events. ***/ - -/* Get the input event type. */ -int32_t AInputEvent_getType(const AInputEvent* event); - -/* Get the id for the device that an input event came from. - * - * Input events can be generated by multiple different input devices. - * Use the input device id to obtain information about the input - * device that was responsible for generating a particular event. - * - * An input device id of 0 indicates that the event didn't come from a physical device; - * other numbers are arbitrary and you shouldn't depend on the values. - * Use the provided input device query API to obtain information about input devices. - */ -int32_t AInputEvent_getDeviceId(const AInputEvent* event); - -/* Get the input event source. */ -int32_t AInputEvent_getSource(const AInputEvent* event); - -/*** Accessors for key events only. ***/ - -/* Get the key event action. */ -int32_t AKeyEvent_getAction(const AInputEvent* key_event); - -/* Get the key event flags. */ -int32_t AKeyEvent_getFlags(const AInputEvent* key_event); - -/* Get the key code of the key event. - * This is the physical key that was pressed, not the Unicode character. */ -int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event); - -/* Get the hardware key id of this key event. - * These values are not reliable and vary from device to device. */ -int32_t AKeyEvent_getScanCode(const AInputEvent* key_event); - -/* Get the meta key state. */ -int32_t AKeyEvent_getMetaState(const AInputEvent* key_event); - -/* Get the repeat count of the event. - * For both key up an key down events, this is the number of times the key has - * repeated with the first down starting at 0 and counting up from there. For - * multiple key events, this is the number of down/up pairs that have occurred. */ -int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event); - -/* Get the time of the most recent key down event, in the - * java.lang.System.nanoTime() time base. If this is a down event, - * this will be the same as eventTime. - * Note that when chording keys, this value is the down time of the most recently - * pressed key, which may not be the same physical key of this event. */ -int64_t AKeyEvent_getDownTime(const AInputEvent* key_event); - -/* Get the time this event occurred, in the - * java.lang.System.nanoTime() time base. */ -int64_t AKeyEvent_getEventTime(const AInputEvent* key_event); - -/*** Accessors for motion events only. ***/ - -/* Get the combined motion event action code and pointer index. */ -int32_t AMotionEvent_getAction(const AInputEvent* motion_event); - -/* Get the motion event flags. */ -int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); - -/* Get the state of any meta / modifier keys that were in effect when the - * event was generated. */ -int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); - -/* Get the button state of all buttons that are pressed. */ -int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); - -/* Get a bitfield indicating which edges, if any, were touched by this motion event. - * For touch events, clients can use this to determine if the user's finger was - * touching the edge of the display. */ -int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event); - -/* Get the time when the user originally pressed down to start a stream of - * position events, in the java.lang.System.nanoTime() time base. */ -int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event); - -/* Get the time when this specific event was generated, - * in the java.lang.System.nanoTime() time base. */ -int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event); - -/* Get the X coordinate offset. - * For touch events on the screen, this is the delta that was added to the raw - * screen coordinates to adjust for the absolute position of the containing windows - * and views. */ -float AMotionEvent_getXOffset(const AInputEvent* motion_event); - -/* Get the precision of the Y coordinates being reported. - * For touch events on the screen, this is the delta that was added to the raw - * screen coordinates to adjust for the absolute position of the containing windows - * and views. */ -float AMotionEvent_getYOffset(const AInputEvent* motion_event); - -/* Get the precision of the X coordinates being reported. - * You can multiply this number with an X coordinate sample to find the - * actual hardware value of the X coordinate. */ -float AMotionEvent_getXPrecision(const AInputEvent* motion_event); - -/* Get the precision of the Y coordinates being reported. - * You can multiply this number with a Y coordinate sample to find the - * actual hardware value of the Y coordinate. */ -float AMotionEvent_getYPrecision(const AInputEvent* motion_event); - -/* Get the number of pointers of data contained in this event. - * Always >= 1. */ -size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); - -/* Get the pointer identifier associated with a particular pointer - * data index in this event. The identifier tells you the actual pointer - * number associated with the data, accounting for individual pointers - * going up and down since the start of the current gesture. */ -int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the tool type of a pointer for the given pointer index. - * The tool type indicates the type of tool used to make contact such as a - * finger or stylus, if known. */ -int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the original raw X coordinate of this event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. */ -float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the original raw X coordinate of this event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. */ -float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current X coordinate of this event for the given pointer index. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current Y coordinate of this event for the given pointer index. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current pressure of this event for the given pointer index. - * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), - * although values higher than 1 may be generated depending on the calibration of - * the input device. */ -float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current scaled value of the approximate size for the given pointer index. - * This represents some approximation of the area of the screen being - * pressed; the actual value in pixels corresponding to the - * touch is normalized with the device specific range of values - * and scaled to a value between 0 and 1. The value of size can be used to - * determine fat touch events. */ -float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the major axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index. */ -float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the minor axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index. */ -float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the major axis of an ellipse that describes the size - * of the approaching tool for the given pointer index. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the minor axis of an ellipse that describes the size - * of the approaching tool for the given pointer index. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current orientation of the touch area and tool area in radians clockwise from - * vertical for the given pointer index. - * An angle of 0 degrees indicates that the major axis of contact is oriented - * upwards, is perfectly circular or is of unknown orientation. A positive angle - * indicates that the major axis of contact is oriented to the right. A negative angle - * indicates that the major axis of contact is oriented to the left. - * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians - * (finger pointing fully right). */ -float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the value of the request axis for the given pointer index. */ -float AMotionEvent_getAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index); - -/* Get the number of historical points in this event. These are movements that - * have occurred between this event and the previous event. This only applies - * to AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0. - * Historical samples are indexed from oldest to newest. */ -size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event); - -/* Get the time that a historical movement occurred between this event and - * the previous event, in the java.lang.System.nanoTime() time base. */ -int64_t AMotionEvent_getHistoricalEventTime(AInputEvent* motion_event, - size_t history_index); - -/* Get the historical raw X coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical raw Y coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical X coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalX(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical Y coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalY(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical pressure of this event for the given pointer index that - * occurred between this event and the previous motion event. - * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), - * although values higher than 1 may be generated depending on the calibration of - * the input device. */ -float AMotionEvent_getHistoricalPressure(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the current scaled value of the approximate size for the given pointer index that - * occurred between this event and the previous motion event. - * This represents some approximation of the area of the screen being - * pressed; the actual value in pixels corresponding to the - * touch is normalized with the device specific range of values - * and scaled to a value between 0 and 1. The value of size can be used to - * determine fat touch events. */ -float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the major axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index that - * occurred between this event and the previous motion event. */ -float AMotionEvent_getHistoricalTouchMajor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the minor axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index that - * occurred between this event and the previous motion event. */ -float AMotionEvent_getHistoricalTouchMinor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the major axis of an ellipse that describes the size - * of the approaching tool for the given pointer index that - * occurred between this event and the previous motion event. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getHistoricalToolMajor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the minor axis of an ellipse that describes the size - * of the approaching tool for the given pointer index that - * occurred between this event and the previous motion event. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical orientation of the touch area and tool area in radians clockwise from - * vertical for the given pointer index that - * occurred between this event and the previous motion event. - * An angle of 0 degrees indicates that the major axis of contact is oriented - * upwards, is perfectly circular or is of unknown orientation. A positive angle - * indicates that the major axis of contact is oriented to the right. A negative angle - * indicates that the major axis of contact is oriented to the left. - * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians - * (finger pointing fully right). */ -float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical value of the request axis for the given pointer index - * that occurred between this event and the previous motion event. */ -float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index, size_t history_index); - - -/* - * Input queue - * - * An input queue is the facility through which you retrieve input - * events. - */ -struct AInputQueue; -typedef struct AInputQueue AInputQueue; - -/* - * Add this input queue to a looper for processing. See - * ALooper_addFd() for information on the ident, callback, and data params. - */ -void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, - int ident, ALooper_callbackFunc callback, void* data); - -/* - * Remove the input queue from the looper it is currently attached to. - */ -void AInputQueue_detachLooper(AInputQueue* queue); - -/* - * Returns true if there are one or more events available in the - * input queue. Returns 1 if the queue has events; 0 if - * it does not have events; and a negative value if there is an error. - */ -int32_t AInputQueue_hasEvents(AInputQueue* queue); - -/* - * Returns the next available event from the queue. Returns a negative - * value if no events are available or an error has occurred. - */ -int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent); - -/* - * Sends the key for standard pre-dispatching -- that is, possibly deliver - * it to the current IME to be consumed before the app. Returns 0 if it - * was not pre-dispatched, meaning you can process it right now. If non-zero - * is returned, you must abandon the current event processing and allow the - * event to appear again in the event queue (if it does not get consumed during - * pre-dispatching). - */ -int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); - -/* - * Report that dispatching has finished with the given event. - * This must be called after receiving an event with AInputQueue_get_event(). - */ -void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); - -#ifdef __cplusplus -} -#endif - -#endif // _ANDROID_INPUT_H diff --git a/widget/gonk/libui/android_keycodes.h b/widget/gonk/libui/android_keycodes.h deleted file mode 100644 index 9e63d1d01..000000000 --- a/widget/gonk/libui/android_keycodes.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * 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. - */ - -#ifndef _ANDROID_KEYCODES_H -#define _ANDROID_KEYCODES_H - -/****************************************************************** - * - * IMPORTANT NOTICE: - * - * This file is part of Android's set of stable system headers - * exposed by the Android NDK (Native Development Kit). - * - * Third-party source AND binary code relies on the definitions - * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. - * - * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) - * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS - * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY - * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES - */ - -#include <sys/types.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Key codes. - */ -enum { - AKEYCODE_UNKNOWN = 0, - AKEYCODE_SOFT_LEFT = 1, - AKEYCODE_SOFT_RIGHT = 2, - AKEYCODE_HOME = 3, - AKEYCODE_BACK = 4, - AKEYCODE_CALL = 5, - AKEYCODE_ENDCALL = 6, - AKEYCODE_0 = 7, - AKEYCODE_1 = 8, - AKEYCODE_2 = 9, - AKEYCODE_3 = 10, - AKEYCODE_4 = 11, - AKEYCODE_5 = 12, - AKEYCODE_6 = 13, - AKEYCODE_7 = 14, - AKEYCODE_8 = 15, - AKEYCODE_9 = 16, - AKEYCODE_STAR = 17, - AKEYCODE_POUND = 18, - AKEYCODE_DPAD_UP = 19, - AKEYCODE_DPAD_DOWN = 20, - AKEYCODE_DPAD_LEFT = 21, - AKEYCODE_DPAD_RIGHT = 22, - AKEYCODE_DPAD_CENTER = 23, - AKEYCODE_VOLUME_UP = 24, - AKEYCODE_VOLUME_DOWN = 25, - AKEYCODE_POWER = 26, - AKEYCODE_CAMERA = 27, - AKEYCODE_CLEAR = 28, - AKEYCODE_A = 29, - AKEYCODE_B = 30, - AKEYCODE_C = 31, - AKEYCODE_D = 32, - AKEYCODE_E = 33, - AKEYCODE_F = 34, - AKEYCODE_G = 35, - AKEYCODE_H = 36, - AKEYCODE_I = 37, - AKEYCODE_J = 38, - AKEYCODE_K = 39, - AKEYCODE_L = 40, - AKEYCODE_M = 41, - AKEYCODE_N = 42, - AKEYCODE_O = 43, - AKEYCODE_P = 44, - AKEYCODE_Q = 45, - AKEYCODE_R = 46, - AKEYCODE_S = 47, - AKEYCODE_T = 48, - AKEYCODE_U = 49, - AKEYCODE_V = 50, - AKEYCODE_W = 51, - AKEYCODE_X = 52, - AKEYCODE_Y = 53, - AKEYCODE_Z = 54, - AKEYCODE_COMMA = 55, - AKEYCODE_PERIOD = 56, - AKEYCODE_ALT_LEFT = 57, - AKEYCODE_ALT_RIGHT = 58, - AKEYCODE_SHIFT_LEFT = 59, - AKEYCODE_SHIFT_RIGHT = 60, - AKEYCODE_TAB = 61, - AKEYCODE_SPACE = 62, - AKEYCODE_SYM = 63, - AKEYCODE_EXPLORER = 64, - AKEYCODE_ENVELOPE = 65, - AKEYCODE_ENTER = 66, - AKEYCODE_DEL = 67, - AKEYCODE_GRAVE = 68, - AKEYCODE_MINUS = 69, - AKEYCODE_EQUALS = 70, - AKEYCODE_LEFT_BRACKET = 71, - AKEYCODE_RIGHT_BRACKET = 72, - AKEYCODE_BACKSLASH = 73, - AKEYCODE_SEMICOLON = 74, - AKEYCODE_APOSTROPHE = 75, - AKEYCODE_SLASH = 76, - AKEYCODE_AT = 77, - AKEYCODE_NUM = 78, - AKEYCODE_HEADSETHOOK = 79, - AKEYCODE_FOCUS = 80, // *Camera* focus - AKEYCODE_PLUS = 81, - AKEYCODE_MENU = 82, - AKEYCODE_NOTIFICATION = 83, - AKEYCODE_SEARCH = 84, - AKEYCODE_MEDIA_PLAY_PAUSE= 85, - AKEYCODE_MEDIA_STOP = 86, - AKEYCODE_MEDIA_NEXT = 87, - AKEYCODE_MEDIA_PREVIOUS = 88, - AKEYCODE_MEDIA_REWIND = 89, - AKEYCODE_MEDIA_FAST_FORWARD = 90, - AKEYCODE_MUTE = 91, - AKEYCODE_PAGE_UP = 92, - AKEYCODE_PAGE_DOWN = 93, - AKEYCODE_PICTSYMBOLS = 94, - AKEYCODE_SWITCH_CHARSET = 95, - AKEYCODE_BUTTON_A = 96, - AKEYCODE_BUTTON_B = 97, - AKEYCODE_BUTTON_C = 98, - AKEYCODE_BUTTON_X = 99, - AKEYCODE_BUTTON_Y = 100, - AKEYCODE_BUTTON_Z = 101, - AKEYCODE_BUTTON_L1 = 102, - AKEYCODE_BUTTON_R1 = 103, - AKEYCODE_BUTTON_L2 = 104, - AKEYCODE_BUTTON_R2 = 105, - AKEYCODE_BUTTON_THUMBL = 106, - AKEYCODE_BUTTON_THUMBR = 107, - AKEYCODE_BUTTON_START = 108, - AKEYCODE_BUTTON_SELECT = 109, - AKEYCODE_BUTTON_MODE = 110, - AKEYCODE_ESCAPE = 111, - AKEYCODE_FORWARD_DEL = 112, - AKEYCODE_CTRL_LEFT = 113, - AKEYCODE_CTRL_RIGHT = 114, - AKEYCODE_CAPS_LOCK = 115, - AKEYCODE_SCROLL_LOCK = 116, - AKEYCODE_META_LEFT = 117, - AKEYCODE_META_RIGHT = 118, - AKEYCODE_FUNCTION = 119, - AKEYCODE_SYSRQ = 120, - AKEYCODE_BREAK = 121, - AKEYCODE_MOVE_HOME = 122, - AKEYCODE_MOVE_END = 123, - AKEYCODE_INSERT = 124, - AKEYCODE_FORWARD = 125, - AKEYCODE_MEDIA_PLAY = 126, - AKEYCODE_MEDIA_PAUSE = 127, - AKEYCODE_MEDIA_CLOSE = 128, - AKEYCODE_MEDIA_EJECT = 129, - AKEYCODE_MEDIA_RECORD = 130, - AKEYCODE_F1 = 131, - AKEYCODE_F2 = 132, - AKEYCODE_F3 = 133, - AKEYCODE_F4 = 134, - AKEYCODE_F5 = 135, - AKEYCODE_F6 = 136, - AKEYCODE_F7 = 137, - AKEYCODE_F8 = 138, - AKEYCODE_F9 = 139, - AKEYCODE_F10 = 140, - AKEYCODE_F11 = 141, - AKEYCODE_F12 = 142, - AKEYCODE_NUM_LOCK = 143, - AKEYCODE_NUMPAD_0 = 144, - AKEYCODE_NUMPAD_1 = 145, - AKEYCODE_NUMPAD_2 = 146, - AKEYCODE_NUMPAD_3 = 147, - AKEYCODE_NUMPAD_4 = 148, - AKEYCODE_NUMPAD_5 = 149, - AKEYCODE_NUMPAD_6 = 150, - AKEYCODE_NUMPAD_7 = 151, - AKEYCODE_NUMPAD_8 = 152, - AKEYCODE_NUMPAD_9 = 153, - AKEYCODE_NUMPAD_DIVIDE = 154, - AKEYCODE_NUMPAD_MULTIPLY = 155, - AKEYCODE_NUMPAD_SUBTRACT = 156, - AKEYCODE_NUMPAD_ADD = 157, - AKEYCODE_NUMPAD_DOT = 158, - AKEYCODE_NUMPAD_COMMA = 159, - AKEYCODE_NUMPAD_ENTER = 160, - AKEYCODE_NUMPAD_EQUALS = 161, - AKEYCODE_NUMPAD_LEFT_PAREN = 162, - AKEYCODE_NUMPAD_RIGHT_PAREN = 163, - AKEYCODE_VOLUME_MUTE = 164, - AKEYCODE_INFO = 165, - AKEYCODE_CHANNEL_UP = 166, - AKEYCODE_CHANNEL_DOWN = 167, - AKEYCODE_ZOOM_IN = 168, - AKEYCODE_ZOOM_OUT = 169, - AKEYCODE_TV = 170, - AKEYCODE_WINDOW = 171, - AKEYCODE_GUIDE = 172, - AKEYCODE_DVR = 173, - AKEYCODE_BOOKMARK = 174, - AKEYCODE_CAPTIONS = 175, - AKEYCODE_SETTINGS = 176, - AKEYCODE_TV_POWER = 177, - AKEYCODE_TV_INPUT = 178, - AKEYCODE_STB_POWER = 179, - AKEYCODE_STB_INPUT = 180, - AKEYCODE_AVR_POWER = 181, - AKEYCODE_AVR_INPUT = 182, - AKEYCODE_PROG_RED = 183, - AKEYCODE_PROG_GREEN = 184, - AKEYCODE_PROG_YELLOW = 185, - AKEYCODE_PROG_BLUE = 186, - AKEYCODE_APP_SWITCH = 187, - AKEYCODE_BUTTON_1 = 188, - AKEYCODE_BUTTON_2 = 189, - AKEYCODE_BUTTON_3 = 190, - AKEYCODE_BUTTON_4 = 191, - AKEYCODE_BUTTON_5 = 192, - AKEYCODE_BUTTON_6 = 193, - AKEYCODE_BUTTON_7 = 194, - AKEYCODE_BUTTON_8 = 195, - AKEYCODE_BUTTON_9 = 196, - AKEYCODE_BUTTON_10 = 197, - AKEYCODE_BUTTON_11 = 198, - AKEYCODE_BUTTON_12 = 199, - AKEYCODE_BUTTON_13 = 200, - AKEYCODE_BUTTON_14 = 201, - AKEYCODE_BUTTON_15 = 202, - AKEYCODE_BUTTON_16 = 203, - AKEYCODE_LANGUAGE_SWITCH = 204, - AKEYCODE_MANNER_MODE = 205, - AKEYCODE_3D_MODE = 206, - AKEYCODE_CONTACTS = 207, - AKEYCODE_CALENDAR = 208, - AKEYCODE_MUSIC = 209, - AKEYCODE_CALCULATOR = 210, - AKEYCODE_ZENKAKU_HANKAKU = 211, - AKEYCODE_EISU = 212, - AKEYCODE_MUHENKAN = 213, - AKEYCODE_HENKAN = 214, - AKEYCODE_KATAKANA_HIRAGANA = 215, - AKEYCODE_YEN = 216, - AKEYCODE_RO = 217, - AKEYCODE_KANA = 218, - AKEYCODE_ASSIST = 219, - AKEYCODE_BRIGHTNESS_DOWN = 220, - AKEYCODE_BRIGHTNESS_UP = 221, - AKEYCODE_MEDIA_AUDIO_TRACK = 222, - AKEYCODE_SLEEP = 223, - AKEYCODE_WAKEUP = 224, - AKEYCODE_PAIRING = 225, - AKEYCODE_MEDIA_TOP_MENU = 226, - AKEYCODE_11 = 227, - AKEYCODE_12 = 228, - AKEYCODE_LAST_CHANNEL = 229, - AKEYCODE_TV_DATA_SERVICE = 230, - AKEYCODE_VOICE_ASSIST = 231, - AKEYCODE_TV_RADIO_SERVICE = 232, - AKEYCODE_TV_TELETEXT = 233, - AKEYCODE_TV_NUMBER_ENTRY = 234, - AKEYCODE_TV_TERRESTRIAL_ANALOG = 235, - AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236, - AKEYCODE_TV_SATELLITE = 237, - AKEYCODE_TV_SATELLITE_BS = 238, - AKEYCODE_TV_SATELLITE_CS = 239, - AKEYCODE_TV_SATELLITE_SERVICE = 240, - AKEYCODE_TV_NETWORK = 241, - AKEYCODE_TV_ANTENNA_CABLE = 242, - AKEYCODE_TV_INPUT_HDMI_1 = 243, - AKEYCODE_TV_INPUT_HDMI_2 = 244, - AKEYCODE_TV_INPUT_HDMI_3 = 245, - AKEYCODE_TV_INPUT_HDMI_4 = 246, - AKEYCODE_TV_INPUT_COMPOSITE_1 = 247, - AKEYCODE_TV_INPUT_COMPOSITE_2 = 248, - AKEYCODE_TV_INPUT_COMPONENT_1 = 249, - AKEYCODE_TV_INPUT_COMPONENT_2 = 250, - AKEYCODE_TV_INPUT_VGA_1 = 251, - AKEYCODE_TV_AUDIO_DESCRIPTION = 252, - AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253, - AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254, - AKEYCODE_TV_ZOOM_MODE = 255, - AKEYCODE_TV_CONTENTS_MENU = 256, - AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257, - AKEYCODE_TV_TIMER_PROGRAMMING = 258, - AKEYCODE_HELP = 259, - - // NOTE: If you add a new keycode here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. -}; - -#ifdef __cplusplus -} -#endif - -#endif // _ANDROID_KEYCODES_H diff --git a/widget/gonk/libui/cutils_log.h b/widget/gonk/libui/cutils_log.h deleted file mode 100644 index f4252c867..000000000 --- a/widget/gonk/libui/cutils_log.h +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * 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. - */ - -// -// C/C++ logging functions. See the logging documentation for API details. -// -// We'd like these to be available from C code (in case we import some from -// somewhere), so this has a C interface. -// -// The output will be correct when the log file is shared between multiple -// threads and/or multiple processes so long as the operating system -// supports O_APPEND. These calls have mutex-protected data structures -// and so are NOT reentrant. Do not use LOG in a signal handler. -// -#if !defined(_LIBS_CUTILS_LOG_H) && !defined(_LIBS_LOG_LOG_H) -#define _LIBS_LOG_LOG_H -#define _LIBS_CUTILS_LOG_H - -#include <stdio.h> -#include <time.h> -#include <sys/types.h> -#include <unistd.h> -#ifdef HAVE_PTHREADS -#include <pthread.h> -#endif -#include <stdarg.h> - -#if ANDROID_VERSION >= 19 -#include <log/uio.h> -#include <log/logd.h> -#else -#include <cutils/uio.h> -#include <cutils/logd.h> -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// --------------------------------------------------------------------- - -/* - * Normally we strip ALOGV (VERBOSE messages) from release builds. - * You can modify this (for example with "#define LOG_NDEBUG 0" - * at the top of your source file) to change that behavior. - */ -#ifndef LOG_NDEBUG -#ifdef NDEBUG -#define LOG_NDEBUG 1 -#else -#define LOG_NDEBUG 0 -#endif -#endif - -/* - * This is the local tag used for the following simplified - * logging macros. You can change this preprocessor definition - * before using the other macros to change the tag. - */ -#ifndef LOG_TAG -#define LOG_TAG NULL -#endif - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose log message using the current LOG_TAG. - */ -#ifndef ALOGV -#if LOG_NDEBUG -#define ALOGV(...) ((void)0) -#else -#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - -#ifndef ALOGV_IF -#if LOG_NDEBUG -#define ALOGV_IF(cond, ...) ((void)0) -#else -#define ALOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug log message using the current LOG_TAG. - */ -#ifndef ALOGD -#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGD_IF -#define ALOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info log message using the current LOG_TAG. - */ -#ifndef ALOGI -#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGI_IF -#define ALOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning log message using the current LOG_TAG. - */ -#ifndef ALOGW -#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGW_IF -#define ALOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error log message using the current LOG_TAG. - */ -#ifndef ALOGE -#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGE_IF -#define ALOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -// --------------------------------------------------------------------- - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * verbose priority. - */ -#ifndef IF_ALOGV -#if LOG_NDEBUG -#define IF_ALOGV() if (false) -#else -#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG) -#endif -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * debug priority. - */ -#ifndef IF_ALOGD -#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * info priority. - */ -#ifndef IF_ALOGI -#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * warn priority. - */ -#ifndef IF_ALOGW -#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * error priority. - */ -#ifndef IF_ALOGE -#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG) -#endif - - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose system log message using the current LOG_TAG. - */ -#ifndef SLOGV -#if LOG_NDEBUG -#define SLOGV(...) ((void)0) -#else -#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - -#ifndef SLOGV_IF -#if LOG_NDEBUG -#define SLOGV_IF(cond, ...) ((void)0) -#else -#define SLOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug system log message using the current LOG_TAG. - */ -#ifndef SLOGD -#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGD_IF -#define SLOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info system log message using the current LOG_TAG. - */ -#ifndef SLOGI -#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGI_IF -#define SLOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning system log message using the current LOG_TAG. - */ -#ifndef SLOGW -#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGW_IF -#define SLOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error system log message using the current LOG_TAG. - */ -#ifndef SLOGE -#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGE_IF -#define SLOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose radio log message using the current LOG_TAG. - */ -#ifndef RLOGV -#if LOG_NDEBUG -#define RLOGV(...) ((void)0) -#else -#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - -#ifndef RLOGV_IF -#if LOG_NDEBUG -#define RLOGV_IF(cond, ...) ((void)0) -#else -#define RLOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug radio log message using the current LOG_TAG. - */ -#ifndef RLOGD -#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGD_IF -#define RLOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info radio log message using the current LOG_TAG. - */ -#ifndef RLOGI -#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGI_IF -#define RLOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning radio log message using the current LOG_TAG. - */ -#ifndef RLOGW -#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGW_IF -#define RLOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error radio log message using the current LOG_TAG. - */ -#ifndef RLOGE -#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGE_IF -#define RLOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - - -// --------------------------------------------------------------------- - -/* - * Log a fatal error. If the given condition fails, this stops program - * execution like a normal assertion, but also generating the given message. - * It is NOT stripped from release builds. Note that the condition test - * is -inverted- from the normal assert() semantics. - */ -#ifndef LOG_ALWAYS_FATAL_IF -#define LOG_ALWAYS_FATAL_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ - : (void)0 ) -#endif - -#ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) \ - ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) -#endif - -/* - * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that - * are stripped out of release builds. - */ -#if LOG_NDEBUG - -#ifndef LOG_FATAL_IF -#define LOG_FATAL_IF(cond, ...) ((void)0) -#endif -#ifndef LOG_FATAL -#define LOG_FATAL(...) ((void)0) -#endif - -#else - -#ifndef LOG_FATAL_IF -#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) -#endif -#ifndef LOG_FATAL -#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) -#endif - -#endif - -/* - * Assertion that generates a log message when the assertion fails. - * Stripped out of release builds. Uses the current LOG_TAG. - */ -#ifndef ALOG_ASSERT -#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) -//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) -#endif - -// --------------------------------------------------------------------- - -/* - * Basic log message macro. - * - * Example: - * ALOG(LOG_WARN, NULL, "Failed with error %d", errno); - * - * The second argument may be NULL or "" to indicate the "global" tag. - */ -#ifndef ALOG -#define ALOG(priority, tag, ...) \ - LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to specify a number for the priority. - */ -#ifndef LOG_PRI -#define LOG_PRI(priority, tag, ...) \ - android_printLog(priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to pass in a varargs ("args" is a va_list). - */ -#ifndef LOG_PRI_VA -#define LOG_PRI_VA(priority, tag, fmt, args) \ - android_vprintLog(priority, NULL, tag, fmt, args) -#endif - -/* - * Conditional given a desired logging priority and tag. - */ -#ifndef IF_ALOG -#define IF_ALOG(priority, tag) \ - if (android_testLog(ANDROID_##priority, tag)) -#endif - -// --------------------------------------------------------------------- - -/* - * Event logging. - */ - -/* - * Event log entry types. These must match up with the declarations in - * java/android/android/util/EventLog.java. - */ -typedef enum { - EVENT_TYPE_INT = 0, - EVENT_TYPE_LONG = 1, - EVENT_TYPE_STRING = 2, - EVENT_TYPE_LIST = 3, -} AndroidEventLogType; - - -#ifndef LOG_EVENT_INT -#define LOG_EVENT_INT(_tag, _value) { \ - int intBuf = _value; \ - (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \ - sizeof(intBuf)); \ - } -#endif -#ifndef LOG_EVENT_LONG -#define LOG_EVENT_LONG(_tag, _value) { \ - long long longBuf = _value; \ - (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \ - sizeof(longBuf)); \ - } -#endif -#ifndef LOG_EVENT_STRING -#define LOG_EVENT_STRING(_tag, _value) \ - ((void) 0) /* not implemented -- must combine len with string */ -#endif -/* TODO: something for LIST */ - -/* - * =========================================================================== - * - * The stuff in the rest of this file should not be used directly. - */ - -#define android_printLog(prio, tag, fmt...) \ - __android_log_print(prio, tag, fmt) - -#define android_vprintLog(prio, cond, tag, fmt...) \ - __android_log_vprint(prio, tag, fmt) - -/* XXX Macros to work around syntax errors in places where format string - * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF - * (happens only in debug builds). - */ - -/* Returns 2nd arg. Used to substitute default value if caller's vararg list - * is empty. - */ -#define __android_second(dummy, second, ...) second - -/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise - * returns nothing. - */ -#define __android_rest(first, ...) , ## __VA_ARGS__ - -#define android_printAssert(cond, tag, fmt...) \ - __android_log_assert(cond, tag, \ - __android_second(0, ## fmt, NULL) __android_rest(fmt)) - -#define android_writeLog(prio, tag, text) \ - __android_log_write(prio, tag, text) - -#define android_bWriteLog(tag, payload, len) \ - __android_log_bwrite(tag, payload, len) -#define android_btWriteLog(tag, type, payload, len) \ - __android_log_btwrite(tag, type, payload, len) - -// TODO: remove these prototypes and their users -#define android_testLog(prio, tag) (1) -#define android_writevLog(vec,num) do{}while(0) -#define android_write1Log(str,len) do{}while (0) -#define android_setMinPriority(tag, prio) do{}while(0) -//#define android_logToCallback(func) do{}while(0) -#define android_logToFile(tag, file) (0) -#define android_logToFd(tag, fd) (0) - -typedef enum { - LOG_ID_MAIN = 0, - LOG_ID_RADIO = 1, - LOG_ID_EVENTS = 2, - LOG_ID_SYSTEM = 3, - - LOG_ID_MAX -} log_id_t; - -/* - * Send a simple string to the log. - */ -int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); -int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...); - - -#ifdef __cplusplus -} -#endif - -#endif // _LIBS_CUTILS_LOG_H diff --git a/widget/gonk/libui/cutils_trace.h b/widget/gonk/libui/cutils_trace.h deleted file mode 100644 index 29034cab5..000000000 --- a/widget/gonk/libui/cutils_trace.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * 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. - */ - -#ifndef _LIBS_CUTILS_TRACE_H -#define _LIBS_CUTILS_TRACE_H - -#include <sys/cdefs.h> -#include <sys/types.h> -#include <stdint.h> -#include <stdbool.h> -#include <unistd.h> -#include <cutils/compiler.h> - -#ifdef ANDROID_SMP -#include <cutils/atomic-inline.h> -#else -#include <cutils/atomic.h> -#endif - -__BEGIN_DECLS - -/** - * The ATRACE_TAG macro can be defined before including this header to trace - * using one of the tags defined below. It must be defined to one of the - * following ATRACE_TAG_* macros. The trace tag is used to filter tracing in - * userland to avoid some of the runtime cost of tracing when it is not desired. - * - * Defining ATRACE_TAG to be ATRACE_TAG_ALWAYS will result in the tracing always - * being enabled - this should ONLY be done for debug code, as userland tracing - * has a performance cost even when the trace is not being recorded. Defining - * ATRACE_TAG to be ATRACE_TAG_NEVER or leaving ATRACE_TAG undefined will result - * in the tracing always being disabled. - * - * ATRACE_TAG_HAL should be bitwise ORed with the relevant tags for tracing - * within a hardware module. For example a camera hardware module would set: - * #define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) - * - * Keep these in sync with frameworks/base/core/java/android/os/Trace.java. - */ -#define ATRACE_TAG_NEVER 0 // This tag is never enabled. -#define ATRACE_TAG_ALWAYS (1<<0) // This tag is always enabled. -#define ATRACE_TAG_GRAPHICS (1<<1) -#define ATRACE_TAG_INPUT (1<<2) -#define ATRACE_TAG_VIEW (1<<3) -#define ATRACE_TAG_WEBVIEW (1<<4) -#define ATRACE_TAG_WINDOW_MANAGER (1<<5) -#define ATRACE_TAG_ACTIVITY_MANAGER (1<<6) -#define ATRACE_TAG_SYNC_MANAGER (1<<7) -#define ATRACE_TAG_AUDIO (1<<8) -#define ATRACE_TAG_VIDEO (1<<9) -#define ATRACE_TAG_CAMERA (1<<10) -#define ATRACE_TAG_HAL (1<<11) -#define ATRACE_TAG_APP (1<<12) -#define ATRACE_TAG_RESOURCES (1<<13) -#define ATRACE_TAG_DALVIK (1<<14) -#define ATRACE_TAG_LAST ATRACE_TAG_DALVIK - -// Reserved for initialization. -#define ATRACE_TAG_NOT_READY (1LL<<63) - -#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST) - -#ifndef ATRACE_TAG -#define ATRACE_TAG ATRACE_TAG_NEVER -#elif ATRACE_TAG > ATRACE_TAG_VALID_MASK -#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h -#endif - -#ifdef HAVE_ANDROID_OS -/** - * Maximum size of a message that can be logged to the trace buffer. - * Note this message includes a tag, the pid, and the string given as the name. - * Names should be kept short to get the most use of the trace buffer. - */ -#define ATRACE_MESSAGE_LENGTH 1024 - -/** - * Opens the trace file for writing and reads the property for initial tags. - * The atrace.tags.enableflags property sets the tags to trace. - * This function should not be explicitly called, the first call to any normal - * trace function will cause it to be run safely. - */ -void atrace_setup(); - -/** - * If tracing is ready, set atrace_enabled_tags to the system property - * debug.atrace.tags.enableflags. Can be used as a sysprop change callback. - */ -void atrace_update_tags(); - -/** - * Set whether the process is debuggable. By default the process is not - * considered debuggable. If the process is not debuggable then application- - * level tracing is not allowed unless the ro.debuggable system property is - * set to '1'. - */ -void atrace_set_debuggable(bool debuggable); - -/** - * Set whether tracing is enabled for the current process. This is used to - * prevent tracing within the Zygote process. - */ -void atrace_set_tracing_enabled(bool enabled); - -/** - * Flag indicating whether setup has been completed, initialized to 0. - * Nonzero indicates setup has completed. - * Note: This does NOT indicate whether or not setup was successful. - */ -extern volatile int32_t atrace_is_ready; - -/** - * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY. - * A value of zero indicates setup has failed. - * Any other nonzero value indicates setup has succeeded, and tracing is on. - */ -extern uint64_t atrace_enabled_tags; - -/** - * Handle to the kernel's trace buffer, initialized to -1. - * Any other value indicates setup has succeeded, and is a valid fd for tracing. - */ -extern int atrace_marker_fd; - -/** - * atrace_init readies the process for tracing by opening the trace_marker file. - * Calling any trace function causes this to be run, so calling it is optional. - * This can be explicitly run to avoid setup delay on first trace function. - */ -#define ATRACE_INIT() atrace_init() -static inline void atrace_init() -{ - if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) { - atrace_setup(); - } -} - -/** - * Get the mask of all tags currently enabled. - * It can be used as a guard condition around more expensive trace calculations. - * Every trace function calls this, which ensures atrace_init is run. - */ -#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags() -static inline uint64_t atrace_get_enabled_tags() -{ - atrace_init(); - return atrace_enabled_tags; -} - -/** - * Test if a given tag is currently enabled. - * Returns nonzero if the tag is enabled, otherwise zero. - * It can be used as a guard condition around more expensive trace calculations. - */ -#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG) -static inline uint64_t atrace_is_tag_enabled(uint64_t tag) -{ - return atrace_get_enabled_tags() & tag; -} - -/** - * Trace the beginning of a context. name is used to identify the context. - * This is often used to time function execution. - */ -#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name) -static inline void atrace_begin(uint64_t tag, const char* name) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name); - write(atrace_marker_fd, buf, len); - } -} - -/** - * Trace the end of a context. - * This should match up (and occur after) a corresponding ATRACE_BEGIN. - */ -#define ATRACE_END() atrace_end(ATRACE_TAG) -static inline void atrace_end(uint64_t tag) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char c = 'E'; - write(atrace_marker_fd, &c, 1); - } -} - -/** - * Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END - * contexts, asynchronous events do not need to be nested. The name describes - * the event, and the cookie provides a unique identifier for distinguishing - * simultaneous events. The name and cookie used to begin an event must be - * used to end it. - */ -#define ATRACE_ASYNC_BEGIN(name, cookie) \ - atrace_async_begin(ATRACE_TAG, name, cookie) -static inline void atrace_async_begin(uint64_t tag, const char* name, - int32_t cookie) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%d", getpid(), - name, cookie); - write(atrace_marker_fd, buf, len); - } -} - -/** - * Trace the end of an asynchronous event. - * This should have a corresponding ATRACE_ASYNC_BEGIN. - */ -#define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie) -static inline void atrace_async_end(uint64_t tag, const char* name, - int32_t cookie) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%d", getpid(), - name, cookie); - write(atrace_marker_fd, buf, len); - } -} - - -/** - * Traces an integer counter value. name is used to identify the counter. - * This can be used to track how a value changes over time. - */ -#define ATRACE_INT(name, value) atrace_int(ATRACE_TAG, name, value) -static inline void atrace_int(uint64_t tag, const char* name, int32_t value) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d", - getpid(), name, value); - write(atrace_marker_fd, buf, len); - } -} - -#else // not HAVE_ANDROID_OS - -#define ATRACE_INIT() -#define ATRACE_GET_ENABLED_TAGS() -#define ATRACE_ENABLED() -#define ATRACE_BEGIN(name) -#define ATRACE_END() -#define ATRACE_ASYNC_BEGIN(name, cookie) -#define ATRACE_ASYNC_END(name, cookie) -#define ATRACE_INT(name, value) - -#endif // not HAVE_ANDROID_OS - -__END_DECLS - -#endif // _LIBS_CUTILS_TRACE_H diff --git a/widget/gonk/libui/linux_input.h b/widget/gonk/libui/linux_input.h deleted file mode 100644 index 2ba14973f..000000000 --- a/widget/gonk/libui/linux_input.h +++ /dev/null @@ -1,1029 +0,0 @@ -/**************************************************************************** - **************************************************************************** - *** - *** This header was automatically generated from a Linux kernel header - *** of the same name, to make information necessary for userspace to - *** call into the kernel available to libc. It contains only constants, - *** structures, and macros generated from the original header, and thus, - *** contains no copyrightable information. - *** - *** To edit the content of this header, modify the corresponding - *** source file (e.g. under external/kernel-headers/original/) then - *** run bionic/libc/kernel/tools/update_all.py - *** - *** Any manual change here will be lost the next time this script will - *** be run. You've been warned! - *** - **************************************************************************** - ****************************************************************************/ -#ifndef _INPUT_H -#define _INPUT_H -#include <sys/time.h> -#include <sys/ioctl.h> -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#include <sys/types.h> -#include <linux/types.h> -struct input_event { - struct timeval time; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 type; - __u16 code; - __s32 value; -}; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_VERSION 0x010001 -struct input_id { - __u16 bustype; - __u16 vendor; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 product; - __u16 version; -}; -struct input_absinfo { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __s32 value; - __s32 minimum; - __s32 maximum; - __s32 fuzz; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __s32 flat; - __s32 resolution; -}; -struct input_keymap_entry { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define INPUT_KEYMAP_BY_INDEX (1 << 0) - __u8 flags; - __u8 len; - __u16 index; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u32 keycode; - __u8 scancode[32]; -}; -#define EVIOCGVERSION _IOR('E', 0x01, int) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGID _IOR('E', 0x02, struct input_id) -#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) -#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) -#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) -#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) -#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) -#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) -#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) -#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) -#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) -#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) -#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) -#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) -#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) -#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) -#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCRMFF _IOW('E', 0x81, int) -#define EVIOCGEFFECTS _IOR('E', 0x84, int) -#define EVIOCGRAB _IOW('E', 0x90, int) -#define EVIOCGSUSPENDBLOCK _IOR('E', 0x91, int) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) -#define EVIOCSCLOCKID _IOW('E', 0xa0, int) -#define INPUT_PROP_POINTER 0x00 -#define INPUT_PROP_DIRECT 0x01 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define INPUT_PROP_BUTTONPAD 0x02 -#define INPUT_PROP_SEMI_MT 0x03 -#define INPUT_PROP_MAX 0x1f -#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_SYN 0x00 -#define EV_KEY 0x01 -#define EV_REL 0x02 -#define EV_ABS 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_MSC 0x04 -#define EV_SW 0x05 -#define EV_LED 0x11 -#define EV_SND 0x12 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_REP 0x14 -#define EV_FF 0x15 -#define EV_PWR 0x16 -#define EV_FF_STATUS 0x17 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_MAX 0x1f -#define EV_CNT (EV_MAX+1) -#define SYN_REPORT 0 -#define SYN_CONFIG 1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SYN_MT_REPORT 2 -#define SYN_DROPPED 3 -#define SYN_TIME_SEC 4 -#define SYN_TIME_NSEC 5 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RESERVED 0 -#define KEY_ESC 1 -#define KEY_1 2 -#define KEY_2 3 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_3 4 -#define KEY_4 5 -#define KEY_5 6 -#define KEY_6 7 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_7 8 -#define KEY_8 9 -#define KEY_9 10 -#define KEY_0 11 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MINUS 12 -#define KEY_EQUAL 13 -#define KEY_BACKSPACE 14 -#define KEY_TAB 15 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_Q 16 -#define KEY_W 17 -#define KEY_E 18 -#define KEY_R 19 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_T 20 -#define KEY_Y 21 -#define KEY_U 22 -#define KEY_I 23 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_O 24 -#define KEY_P 25 -#define KEY_LEFTBRACE 26 -#define KEY_RIGHTBRACE 27 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_ENTER 28 -#define KEY_LEFTCTRL 29 -#define KEY_A 30 -#define KEY_S 31 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_D 32 -#define KEY_F 33 -#define KEY_G 34 -#define KEY_H 35 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_J 36 -#define KEY_K 37 -#define KEY_L 38 -#define KEY_SEMICOLON 39 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_APOSTROPHE 40 -#define KEY_GRAVE 41 -#define KEY_LEFTSHIFT 42 -#define KEY_BACKSLASH 43 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_Z 44 -#define KEY_X 45 -#define KEY_C 46 -#define KEY_V 47 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_B 48 -#define KEY_N 49 -#define KEY_M 50 -#define KEY_COMMA 51 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DOT 52 -#define KEY_SLASH 53 -#define KEY_RIGHTSHIFT 54 -#define KEY_KPASTERISK 55 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_LEFTALT 56 -#define KEY_SPACE 57 -#define KEY_CAPSLOCK 58 -#define KEY_F1 59 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F2 60 -#define KEY_F3 61 -#define KEY_F4 62 -#define KEY_F5 63 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F6 64 -#define KEY_F7 65 -#define KEY_F8 66 -#define KEY_F9 67 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F10 68 -#define KEY_NUMLOCK 69 -#define KEY_SCROLLLOCK 70 -#define KEY_KP7 71 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KP8 72 -#define KEY_KP9 73 -#define KEY_KPMINUS 74 -#define KEY_KP4 75 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KP5 76 -#define KEY_KP6 77 -#define KEY_KPPLUS 78 -#define KEY_KP1 79 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KP2 80 -#define KEY_KP3 81 -#define KEY_KP0 82 -#define KEY_KPDOT 83 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_ZENKAKUHANKAKU 85 -#define KEY_102ND 86 -#define KEY_F11 87 -#define KEY_F12 88 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RO 89 -#define KEY_KATAKANA 90 -#define KEY_HIRAGANA 91 -#define KEY_HENKAN 92 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KATAKANAHIRAGANA 93 -#define KEY_MUHENKAN 94 -#define KEY_KPJPCOMMA 95 -#define KEY_KPENTER 96 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RIGHTCTRL 97 -#define KEY_KPSLASH 98 -#define KEY_SYSRQ 99 -#define KEY_RIGHTALT 100 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_LINEFEED 101 -#define KEY_HOME 102 -#define KEY_UP 103 -#define KEY_PAGEUP 104 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_LEFT 105 -#define KEY_RIGHT 106 -#define KEY_END 107 -#define KEY_DOWN 108 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PAGEDOWN 109 -#define KEY_INSERT 110 -#define KEY_DELETE 111 -#define KEY_MACRO 112 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MUTE 113 -#define KEY_VOLUMEDOWN 114 -#define KEY_VOLUMEUP 115 -#define KEY_POWER 116 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KPEQUAL 117 -#define KEY_KPPLUSMINUS 118 -#define KEY_PAUSE 119 -#define KEY_SCALE 120 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KPCOMMA 121 -#define KEY_HANGEUL 122 -#define KEY_HANGUEL KEY_HANGEUL -#define KEY_HANJA 123 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_YEN 124 -#define KEY_LEFTMETA 125 -#define KEY_RIGHTMETA 126 -#define KEY_COMPOSE 127 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_STOP 128 -#define KEY_AGAIN 129 -#define KEY_PROPS 130 -#define KEY_UNDO 131 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FRONT 132 -#define KEY_COPY 133 -#define KEY_OPEN 134 -#define KEY_PASTE 135 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FIND 136 -#define KEY_CUT 137 -#define KEY_HELP 138 -#define KEY_MENU 139 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CALC 140 -#define KEY_SETUP 141 -#define KEY_SLEEP 142 -#define KEY_WAKEUP 143 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FILE 144 -#define KEY_SENDFILE 145 -#define KEY_DELETEFILE 146 -#define KEY_XFER 147 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PROG1 148 -#define KEY_PROG2 149 -#define KEY_WWW 150 -#define KEY_MSDOS 151 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_COFFEE 152 -#define KEY_SCREENLOCK KEY_COFFEE -#define KEY_DIRECTION 153 -#define KEY_CYCLEWINDOWS 154 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MAIL 155 -#define KEY_BOOKMARKS 156 -#define KEY_COMPUTER 157 -#define KEY_BACK 158 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FORWARD 159 -#define KEY_CLOSECD 160 -#define KEY_EJECTCD 161 -#define KEY_EJECTCLOSECD 162 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NEXTSONG 163 -#define KEY_PLAYPAUSE 164 -#define KEY_PREVIOUSSONG 165 -#define KEY_STOPCD 166 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RECORD 167 -#define KEY_REWIND 168 -#define KEY_PHONE 169 -#define KEY_ISO 170 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CONFIG 171 -#define KEY_HOMEPAGE 172 -#define KEY_REFRESH 173 -#define KEY_EXIT 174 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MOVE 175 -#define KEY_EDIT 176 -#define KEY_SCROLLUP 177 -#define KEY_SCROLLDOWN 178 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KPLEFTPAREN 179 -#define KEY_KPRIGHTPAREN 180 -#define KEY_NEW 181 -#define KEY_REDO 182 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F13 183 -#define KEY_F14 184 -#define KEY_F15 185 -#define KEY_F16 186 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F17 187 -#define KEY_F18 188 -#define KEY_F19 189 -#define KEY_F20 190 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F21 191 -#define KEY_F22 192 -#define KEY_F23 193 -#define KEY_F24 194 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PLAYCD 200 -#define KEY_PAUSECD 201 -#define KEY_PROG3 202 -#define KEY_PROG4 203 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DASHBOARD 204 -#define KEY_SUSPEND 205 -#define KEY_CLOSE 206 -#define KEY_PLAY 207 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FASTFORWARD 208 -#define KEY_BASSBOOST 209 -#define KEY_PRINT 210 -#define KEY_HP 211 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CAMERA 212 -#define KEY_SOUND 213 -#define KEY_QUESTION 214 -#define KEY_EMAIL 215 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CHAT 216 -#define KEY_SEARCH 217 -#define KEY_CONNECT 218 -#define KEY_FINANCE 219 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SPORT 220 -#define KEY_SHOP 221 -#define KEY_ALTERASE 222 -#define KEY_CANCEL 223 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRIGHTNESSDOWN 224 -#define KEY_BRIGHTNESSUP 225 -#define KEY_MEDIA 226 -#define KEY_SWITCHVIDEOMODE 227 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KBDILLUMTOGGLE 228 -#define KEY_KBDILLUMDOWN 229 -#define KEY_KBDILLUMUP 230 -#define KEY_SEND 231 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_REPLY 232 -#define KEY_FORWARDMAIL 233 -#define KEY_SAVE 234 -#define KEY_DOCUMENTS 235 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BATTERY 236 -#define KEY_BLUETOOTH 237 -#define KEY_WLAN 238 -#define KEY_UWB 239 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_UNKNOWN 240 -#define KEY_VIDEO_NEXT 241 -#define KEY_VIDEO_PREV 242 -#define KEY_BRIGHTNESS_CYCLE 243 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRIGHTNESS_ZERO 244 -#define KEY_DISPLAY_OFF 245 -#define KEY_WIMAX 246 -#define KEY_RFKILL 247 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MICMUTE 248 -#define BTN_MISC 0x100 -#define BTN_0 0x100 -#define BTN_1 0x101 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_2 0x102 -#define BTN_3 0x103 -#define BTN_4 0x104 -#define BTN_5 0x105 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_6 0x106 -#define BTN_7 0x107 -#define BTN_8 0x108 -#define BTN_9 0x109 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_MOUSE 0x110 -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_SIDE 0x113 -#define BTN_EXTRA 0x114 -#define BTN_FORWARD 0x115 -#define BTN_BACK 0x116 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TASK 0x117 -#define BTN_JOYSTICK 0x120 -#define BTN_TRIGGER 0x120 -#define BTN_THUMB 0x121 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_THUMB2 0x122 -#define BTN_TOP 0x123 -#define BTN_TOP2 0x124 -#define BTN_PINKIE 0x125 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_BASE 0x126 -#define BTN_BASE2 0x127 -#define BTN_BASE3 0x128 -#define BTN_BASE4 0x129 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_BASE5 0x12a -#define BTN_BASE6 0x12b -#define BTN_DEAD 0x12f -#define BTN_GAMEPAD 0x130 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_A 0x130 -#define BTN_B 0x131 -#define BTN_C 0x132 -#define BTN_X 0x133 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_Y 0x134 -#define BTN_Z 0x135 -#define BTN_TL 0x136 -#define BTN_TR 0x137 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TL2 0x138 -#define BTN_TR2 0x139 -#define BTN_SELECT 0x13a -#define BTN_START 0x13b -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_MODE 0x13c -#define BTN_THUMBL 0x13d -#define BTN_THUMBR 0x13e -#define BTN_DIGI 0x140 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_PEN 0x140 -#define BTN_TOOL_RUBBER 0x141 -#define BTN_TOOL_BRUSH 0x142 -#define BTN_TOOL_PENCIL 0x143 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_AIRBRUSH 0x144 -#define BTN_TOOL_FINGER 0x145 -#define BTN_TOOL_MOUSE 0x146 -#define BTN_TOOL_LENS 0x147 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_QUINTTAP 0x148 -#define BTN_TOUCH 0x14a -#define BTN_STYLUS 0x14b -#define BTN_STYLUS2 0x14c -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_DOUBLETAP 0x14d -#define BTN_TOOL_TRIPLETAP 0x14e -#define BTN_TOOL_QUADTAP 0x14f -#define BTN_WHEEL 0x150 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_GEAR_DOWN 0x150 -#define BTN_GEAR_UP 0x151 -#define KEY_OK 0x160 -#define KEY_SELECT 0x161 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_GOTO 0x162 -#define KEY_CLEAR 0x163 -#define KEY_POWER2 0x164 -#define KEY_OPTION 0x165 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_INFO 0x166 -#define KEY_TIME 0x167 -#define KEY_VENDOR 0x168 -#define KEY_ARCHIVE 0x169 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PROGRAM 0x16a -#define KEY_CHANNEL 0x16b -#define KEY_FAVORITES 0x16c -#define KEY_EPG 0x16d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PVR 0x16e -#define KEY_MHP 0x16f -#define KEY_LANGUAGE 0x170 -#define KEY_TITLE 0x171 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SUBTITLE 0x172 -#define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 -#define KEY_MODE 0x175 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 -#define KEY_PC 0x178 -#define KEY_TV 0x179 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TV2 0x17a -#define KEY_VCR 0x17b -#define KEY_VCR2 0x17c -#define KEY_SAT 0x17d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SAT2 0x17e -#define KEY_CD 0x17f -#define KEY_TAPE 0x180 -#define KEY_RADIO 0x181 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TUNER 0x182 -#define KEY_PLAYER 0x183 -#define KEY_TEXT 0x184 -#define KEY_DVD 0x185 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_AUX 0x186 -#define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 -#define KEY_VIDEO 0x189 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DIRECTORY 0x18a -#define KEY_LIST 0x18b -#define KEY_MEMO 0x18c -#define KEY_CALENDAR 0x18d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RED 0x18e -#define KEY_GREEN 0x18f -#define KEY_YELLOW 0x190 -#define KEY_BLUE 0x191 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CHANNELUP 0x192 -#define KEY_CHANNELDOWN 0x193 -#define KEY_FIRST 0x194 -#define KEY_LAST 0x195 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_AB 0x196 -#define KEY_NEXT 0x197 -#define KEY_RESTART 0x198 -#define KEY_SLOW 0x199 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SHUFFLE 0x19a -#define KEY_BREAK 0x19b -#define KEY_PREVIOUS 0x19c -#define KEY_DIGITS 0x19d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TEEN 0x19e -#define KEY_TWEN 0x19f -#define KEY_VIDEOPHONE 0x1a0 -#define KEY_GAMES 0x1a1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_ZOOMIN 0x1a2 -#define KEY_ZOOMOUT 0x1a3 -#define KEY_ZOOMRESET 0x1a4 -#define KEY_WORDPROCESSOR 0x1a5 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_EDITOR 0x1a6 -#define KEY_SPREADSHEET 0x1a7 -#define KEY_GRAPHICSEDITOR 0x1a8 -#define KEY_PRESENTATION 0x1a9 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DATABASE 0x1aa -#define KEY_NEWS 0x1ab -#define KEY_VOICEMAIL 0x1ac -#define KEY_ADDRESSBOOK 0x1ad -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MESSENGER 0x1ae -#define KEY_DISPLAYTOGGLE 0x1af -#define KEY_SPELLCHECK 0x1b0 -#define KEY_LOGOFF 0x1b1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DOLLAR 0x1b2 -#define KEY_EURO 0x1b3 -#define KEY_FRAMEBACK 0x1b4 -#define KEY_FRAMEFORWARD 0x1b5 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CONTEXT_MENU 0x1b6 -#define KEY_MEDIA_REPEAT 0x1b7 -#define KEY_10CHANNELSUP 0x1b8 -#define KEY_10CHANNELSDOWN 0x1b9 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_IMAGES 0x1ba -#define KEY_DEL_EOL 0x1c0 -#define KEY_DEL_EOS 0x1c1 -#define KEY_INS_LINE 0x1c2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DEL_LINE 0x1c3 -#define KEY_FN 0x1d0 -#define KEY_FN_ESC 0x1d1 -#define KEY_FN_F1 0x1d2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_F2 0x1d3 -#define KEY_FN_F3 0x1d4 -#define KEY_FN_F4 0x1d5 -#define KEY_FN_F5 0x1d6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_F6 0x1d7 -#define KEY_FN_F7 0x1d8 -#define KEY_FN_F8 0x1d9 -#define KEY_FN_F9 0x1da -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_F10 0x1db -#define KEY_FN_F11 0x1dc -#define KEY_FN_F12 0x1dd -#define KEY_FN_1 0x1de -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_2 0x1df -#define KEY_FN_D 0x1e0 -#define KEY_FN_E 0x1e1 -#define KEY_FN_F 0x1e2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_S 0x1e3 -#define KEY_FN_B 0x1e4 -#define KEY_BRL_DOT1 0x1f1 -#define KEY_BRL_DOT2 0x1f2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRL_DOT3 0x1f3 -#define KEY_BRL_DOT4 0x1f4 -#define KEY_BRL_DOT5 0x1f5 -#define KEY_BRL_DOT6 0x1f6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRL_DOT7 0x1f7 -#define KEY_BRL_DOT8 0x1f8 -#define KEY_BRL_DOT9 0x1f9 -#define KEY_BRL_DOT10 0x1fa -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NUMERIC_0 0x200 -#define KEY_NUMERIC_1 0x201 -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CAMERA_SNAPSHOT 0x2fe -#define KEY_CAMERA_FOCUS 0x210 -#define KEY_WPS_BUTTON 0x211 -#define KEY_TOUCHPAD_TOGGLE 0x212 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TOUCHPAD_ON 0x213 -#define KEY_TOUCHPAD_OFF 0x214 -#define KEY_CAMERA_ZOOMIN 0x215 -#define KEY_CAMERA_ZOOMOUT 0x216 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CAMERA_UP 0x217 -#define KEY_CAMERA_DOWN 0x218 -#define KEY_CAMERA_LEFT 0x219 -#define KEY_CAMERA_RIGHT 0x21a -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY 0x2c0 -#define BTN_TRIGGER_HAPPY1 0x2c0 -#define BTN_TRIGGER_HAPPY2 0x2c1 -#define BTN_TRIGGER_HAPPY3 0x2c2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY4 0x2c3 -#define BTN_TRIGGER_HAPPY5 0x2c4 -#define BTN_TRIGGER_HAPPY6 0x2c5 -#define BTN_TRIGGER_HAPPY7 0x2c6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY8 0x2c7 -#define BTN_TRIGGER_HAPPY9 0x2c8 -#define BTN_TRIGGER_HAPPY10 0x2c9 -#define BTN_TRIGGER_HAPPY11 0x2ca -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY12 0x2cb -#define BTN_TRIGGER_HAPPY13 0x2cc -#define BTN_TRIGGER_HAPPY14 0x2cd -#define BTN_TRIGGER_HAPPY15 0x2ce -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY16 0x2cf -#define BTN_TRIGGER_HAPPY17 0x2d0 -#define BTN_TRIGGER_HAPPY18 0x2d1 -#define BTN_TRIGGER_HAPPY19 0x2d2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY20 0x2d3 -#define BTN_TRIGGER_HAPPY21 0x2d4 -#define BTN_TRIGGER_HAPPY22 0x2d5 -#define BTN_TRIGGER_HAPPY23 0x2d6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY24 0x2d7 -#define BTN_TRIGGER_HAPPY25 0x2d8 -#define BTN_TRIGGER_HAPPY26 0x2d9 -#define BTN_TRIGGER_HAPPY27 0x2da -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY28 0x2db -#define BTN_TRIGGER_HAPPY29 0x2dc -#define BTN_TRIGGER_HAPPY30 0x2dd -#define BTN_TRIGGER_HAPPY31 0x2de -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY32 0x2df -#define BTN_TRIGGER_HAPPY33 0x2e0 -#define BTN_TRIGGER_HAPPY34 0x2e1 -#define BTN_TRIGGER_HAPPY35 0x2e2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY36 0x2e3 -#define BTN_TRIGGER_HAPPY37 0x2e4 -#define BTN_TRIGGER_HAPPY38 0x2e5 -#define BTN_TRIGGER_HAPPY39 0x2e6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY40 0x2e7 -#define KEY_MIN_INTERESTING KEY_MUTE -#define KEY_MAX 0x2ff -#define KEY_CNT (KEY_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REL_X 0x00 -#define REL_Y 0x01 -#define REL_Z 0x02 -#define REL_RX 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REL_RY 0x04 -#define REL_RZ 0x05 -#define REL_HWHEEL 0x06 -#define REL_DIAL 0x07 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REL_WHEEL 0x08 -#define REL_MISC 0x09 -#define REL_MAX 0x0f -#define REL_CNT (REL_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_X 0x00 -#define ABS_Y 0x01 -#define ABS_Z 0x02 -#define ABS_RX 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_RY 0x04 -#define ABS_RZ 0x05 -#define ABS_THROTTLE 0x06 -#define ABS_RUDDER 0x07 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_WHEEL 0x08 -#define ABS_GAS 0x09 -#define ABS_BRAKE 0x0a -#define ABS_HAT0X 0x10 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_HAT0Y 0x11 -#define ABS_HAT1X 0x12 -#define ABS_HAT1Y 0x13 -#define ABS_HAT2X 0x14 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_HAT2Y 0x15 -#define ABS_HAT3X 0x16 -#define ABS_HAT3Y 0x17 -#define ABS_PRESSURE 0x18 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_DISTANCE 0x19 -#define ABS_TILT_X 0x1a -#define ABS_TILT_Y 0x1b -#define ABS_TOOL_WIDTH 0x1c -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_VOLUME 0x20 -#define ABS_MISC 0x28 -#define ABS_MT_SLOT 0x2f -#define ABS_MT_TOUCH_MAJOR 0x30 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_MT_TOUCH_MINOR 0x31 -#define ABS_MT_WIDTH_MAJOR 0x32 -#define ABS_MT_WIDTH_MINOR 0x33 -#define ABS_MT_ORIENTATION 0x34 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_MT_POSITION_X 0x35 -#define ABS_MT_POSITION_Y 0x36 -#define ABS_MT_TOOL_TYPE 0x37 -#define ABS_MT_BLOB_ID 0x38 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_MT_TRACKING_ID 0x39 -#define ABS_MT_PRESSURE 0x3a -#define ABS_MT_DISTANCE 0x3b -#define ABS_MAX 0x3f -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_CNT (ABS_MAX+1) -#define SW_LID 0x00 -#define SW_TABLET_MODE 0x01 -#define SW_HEADPHONE_INSERT 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_RFKILL_ALL 0x03 -#define SW_RADIO SW_RFKILL_ALL -#define SW_MICROPHONE_INSERT 0x04 -#define SW_DOCK 0x05 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_LINEOUT_INSERT 0x06 -#define SW_JACK_PHYSICAL_INSERT 0x07 -#define SW_VIDEOOUT_INSERT 0x08 -#define SW_CAMERA_LENS_COVER 0x09 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_KEYPAD_SLIDE 0x0a -#define SW_FRONT_PROXIMITY 0x0b -#define SW_ROTATE_LOCK 0x0c -#define SW_LINEIN_INSERT 0x0d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_HPHL_OVERCURRENT 0x0e -#define SW_HPHR_OVERCURRENT 0x0f -#define SW_UNSUPPORT_INSERT 0x10 -#define SW_MAX 0x20 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_CNT (SW_MAX+1) -#define MSC_SERIAL 0x00 -#define MSC_PULSELED 0x01 -#define MSC_GESTURE 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define MSC_RAW 0x03 -#define MSC_SCAN 0x04 -#define MSC_MAX 0x07 -#define MSC_CNT (MSC_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_NUML 0x00 -#define LED_CAPSL 0x01 -#define LED_SCROLLL 0x02 -#define LED_COMPOSE 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_KANA 0x04 -#define LED_SLEEP 0x05 -#define LED_SUSPEND 0x06 -#define LED_MUTE 0x07 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_MISC 0x08 -#define LED_MAIL 0x09 -#define LED_CHARGING 0x0a -#define LED_MAX 0x0f -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_CNT (LED_MAX+1) -#define REP_DELAY 0x00 -#define REP_PERIOD 0x01 -#define REP_MAX 0x01 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REP_CNT (REP_MAX+1) -#define SND_CLICK 0x00 -#define SND_BELL 0x01 -#define SND_TONE 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SND_MAX 0x07 -#define SND_CNT (SND_MAX+1) -#define ID_BUS 0 -#define ID_VENDOR 1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ID_PRODUCT 2 -#define ID_VERSION 3 -#define BUS_PCI 0x01 -#define BUS_ISAPNP 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_USB 0x03 -#define BUS_HIL 0x04 -#define BUS_BLUETOOTH 0x05 -#define BUS_VIRTUAL 0x06 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_ISA 0x10 -#define BUS_I8042 0x11 -#define BUS_XTKBD 0x12 -#define BUS_RS232 0x13 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_GAMEPORT 0x14 -#define BUS_PARPORT 0x15 -#define BUS_AMIGA 0x16 -#define BUS_ADB 0x17 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_I2C 0x18 -#define BUS_HOST 0x19 -#define BUS_GSC 0x1A -#define BUS_ATARI 0x1B -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_SPI 0x1C -#define MT_TOOL_FINGER 0 -#define MT_TOOL_PEN 1 -#define MT_TOOL_MAX 1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_STATUS_STOPPED 0x00 -#define FF_STATUS_PLAYING 0x01 -#define FF_STATUS_MAX 0x01 -struct ff_replay { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 length; - __u16 delay; -}; -struct ff_trigger { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 button; - __u16 interval; -}; -struct ff_envelope { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 attack_length; - __u16 attack_level; - __u16 fade_length; - __u16 fade_level; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -}; -struct ff_constant_effect { - __s16 level; - struct ff_envelope envelope; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -}; -struct ff_ramp_effect { - __s16 start_level; - __s16 end_level; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_envelope envelope; -}; -struct ff_condition_effect { - __u16 right_saturation; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 left_saturation; - __s16 right_coeff; - __s16 left_coeff; - __u16 deadband; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __s16 center; -}; -struct ff_periodic_effect { - __u16 waveform; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_envelope envelope; - __u32 custom_len; - __s16 __user *custom_data; -}; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -struct ff_rumble_effect { - __u16 strong_magnitude; - __u16 weak_magnitude; -}; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -struct ff_effect { - __u16 type; - __s16 id; - __u16 direction; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_trigger trigger; - struct ff_replay replay; - union { - struct ff_constant_effect constant; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_ramp_effect ramp; - struct ff_periodic_effect periodic; - struct ff_condition_effect condition[2]; - struct ff_rumble_effect rumble; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - } u; -}; -#define FF_RUMBLE 0x50 -#define FF_PERIODIC 0x51 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_CONSTANT 0x52 -#define FF_SPRING 0x53 -#define FF_FRICTION 0x54 -#define FF_DAMPER 0x55 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_INERTIA 0x56 -#define FF_RAMP 0x57 -#define FF_EFFECT_MIN FF_RUMBLE -#define FF_EFFECT_MAX FF_RAMP -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_SQUARE 0x58 -#define FF_TRIANGLE 0x59 -#define FF_SINE 0x5a -#define FF_SAW_UP 0x5b -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_SAW_DOWN 0x5c -#define FF_CUSTOM 0x5d -#define FF_WAVEFORM_MIN FF_SQUARE -#define FF_WAVEFORM_MAX FF_CUSTOM -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_GAIN 0x60 -#define FF_AUTOCENTER 0x61 -#define FF_MAX 0x7f -#define FF_CNT (FF_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#endif diff --git a/widget/gonk/libui/sha1.c b/widget/gonk/libui/sha1.c deleted file mode 100644 index 40a4ecaa3..000000000 --- a/widget/gonk/libui/sha1.c +++ /dev/null @@ -1,289 +0,0 @@ -/* $NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $ */ -/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */ - -/* - * SHA-1 in C - * By Steve Reid <steve@edmweb.com> - * 100% Public Domain - * - * Test Vectors (from FIPS PUB 180-1) - * "abc" - * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - * A million repetitions of "a" - * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F - */ - -#define SHA1HANDSOFF /* Copies data before messing with it. */ - -#include <sys/cdefs.h> - -#if defined(_KERNEL) || defined(_STANDALONE) -__KERNEL_RCSID(0, "$NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $"); - -#include <lib/libkern/libkern.h> - -#else - -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include <assert.h> -#include <string.h> - -#endif - -#include <sys/types.h> -#include "sha1.h" - -#define _DIAGASSERT assert - -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#endif - -#if !HAVE_SHA1_H - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* - * blk0() and blk() perform the initial expand. - * I got the idea of expanding during the round function from SSLeay - */ -#if BYTE_ORDER == LITTLE_ENDIAN -# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -# define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* - * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 - */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -#if !defined(_KERNEL) && !defined(_STANDALONE) -#if defined(__weak_alias) -__weak_alias(SHA1Transform,_SHA1Transform) -__weak_alias(SHA1Init,_SHA1Init) -__weak_alias(SHA1Update,_SHA1Update) -__weak_alias(SHA1Final,_SHA1Final) -#endif -#endif - -typedef union { - uint8_t c[64]; - uint32_t l[16]; -} CHAR64LONG16; - -/* old sparc64 gcc could not compile this */ -#undef SPARC64_GCC_WORKAROUND -#if defined(__sparc64__) && defined(__GNUC__) && __GNUC__ < 3 -#define SPARC64_GCC_WORKAROUND -#endif - -#ifdef SPARC64_GCC_WORKAROUND -void do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); -void do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); -void do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); -void do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); - -#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i) -#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i) -#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i) -#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i) -#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i) - -void -do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2); nR0(c,d,e,a,b, 3); - nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5); nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); - nR0(c,d,e,a,b, 8); nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11); - nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14); nR0(a,b,c,d,e,15); - nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17); nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19); -} - -void -do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22); nR2(c,d,e,a,b,23); - nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25); nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); - nR2(c,d,e,a,b,28); nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31); - nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34); nR2(a,b,c,d,e,35); - nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37); nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39); -} - -void -do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42); nR3(c,d,e,a,b,43); - nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45); nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); - nR3(c,d,e,a,b,48); nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51); - nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54); nR3(a,b,c,d,e,55); - nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57); nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59); -} - -void -do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62); nR4(c,d,e,a,b,63); - nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65); nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); - nR4(c,d,e,a,b,68); nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71); - nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74); nR4(a,b,c,d,e,75); - nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77); nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79); -} -#endif - -/* - * Hash a single 512-bit block. This is the core of the algorithm. - */ -void SHA1Transform(uint32_t state[5], const uint8_t buffer[64]) -{ - uint32_t a, b, c, d, e; - CHAR64LONG16 *block; - -#ifdef SHA1HANDSOFF - CHAR64LONG16 workspace; -#endif - - _DIAGASSERT(buffer != 0); - _DIAGASSERT(state != 0); - -#ifdef SHA1HANDSOFF - block = &workspace; - (void)memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16 *)(void *)buffer; -#endif - - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - -#ifdef SPARC64_GCC_WORKAROUND - do_R01(&a, &b, &c, &d, &e, block); - do_R2(&a, &b, &c, &d, &e, block); - do_R3(&a, &b, &c, &d, &e, block); - do_R4(&a, &b, &c, &d, &e, block); -#else - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); -#endif - - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* - * SHA1Init - Initialize new context - */ -void SHA1Init(SHA1_CTX *context) -{ - - _DIAGASSERT(context != 0); - - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* - * Run your data through this. - */ -void SHA1Update(SHA1_CTX *context, const uint8_t *data, unsigned int len) -{ - unsigned int i, j; - - _DIAGASSERT(context != 0); - _DIAGASSERT(data != 0); - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1] += (len>>29)+1; - j = (j >> 3) & 63; - if ((j + len) > 63) { - (void)memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) - SHA1Transform(context->state, &data[i]); - j = 0; - } else { - i = 0; - } - (void)memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* - * Add padding and return the message digest. - */ -void SHA1Final(uint8_t digest[20], SHA1_CTX *context) -{ - unsigned int i; - uint8_t finalcount[8]; - - _DIAGASSERT(digest != 0); - _DIAGASSERT(context != 0); - - for (i = 0; i < 8; i++) { - finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (const uint8_t *)"\200", 1); - while ((context->count[0] & 504) != 448) - SHA1Update(context, (const uint8_t *)"\0", 1); - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - - if (digest) { - for (i = 0; i < 20; i++) - digest[i] = (uint8_t) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } -} - -#endif /* HAVE_SHA1_H */ diff --git a/widget/gonk/libui/sha1.h b/widget/gonk/libui/sha1.h deleted file mode 100644 index f7ada46a5..000000000 --- a/widget/gonk/libui/sha1.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $NetBSD: sha1.h,v 1.13 2005/12/26 18:41:36 perry Exp $ */ - -/* - * SHA-1 in C - * By Steve Reid <steve@edmweb.com> - * 100% Public Domain - */ - -#ifndef _SYS_SHA1_H_ -#define _SYS_SHA1_H_ - -#include <sys/cdefs.h> -#include <sys/types.h> - -#define SHA1_DIGEST_LENGTH 20 -#define SHA1_DIGEST_STRING_LENGTH 41 - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - u_char buffer[64]; -} SHA1_CTX; - -__BEGIN_DECLS -void SHA1Transform(uint32_t[5], const u_char[64]); -void SHA1Init(SHA1_CTX *); -void SHA1Update(SHA1_CTX *, const u_char *, u_int); -void SHA1Final(u_char[SHA1_DIGEST_LENGTH], SHA1_CTX *); -__END_DECLS - -#endif /* _SYS_SHA1_H_ */ diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build deleted file mode 100644 index d539dd9a0..000000000 --- a/widget/gonk/moz.build +++ /dev/null @@ -1,96 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -EXPORTS += [ - 'GeckoTouchDispatcher.h', - 'GonkPermission.h', - 'OrientationObserver.h', -] - -DIRS += ['libdisplay', 'nativewindow'] - -# libui files -SOURCES += ['libui/' + src for src in [ - 'EventHub.cpp', - 'Input.cpp', - 'InputApplication.cpp', - 'InputDevice.cpp', - 'InputDispatcher.cpp', - 'InputListener.cpp', - 'InputReader.cpp', - 'InputTransport.cpp', - 'InputWindow.cpp', - 'Keyboard.cpp', - 'KeyCharacterMap.cpp', - 'KeyLayoutMap.cpp', - 'PointerController.cpp', - 'sha1.c', - 'SpriteController.cpp', - 'Tokenizer.cpp', - 'VelocityControl.cpp', - 'VelocityTracker.cpp', - 'VirtualKeyMap.cpp', -]] - -# HwcHAL files -if CONFIG['ANDROID_VERSION'] >= '17': - SOURCES += [ - 'hwchal/HwcHAL.cpp', - ] - -SOURCES += [ - 'GeckoTouchDispatcher.cpp', - 'GfxInfo.cpp', - 'GonkClipboardData.cpp', - 'GonkMemoryPressureMonitoring.cpp', - 'GonkPermission.cpp', - 'HwcComposer2D.cpp', - 'HwcUtils.cpp', - 'nsAppShell.cpp', - 'nsClipboard.cpp', - 'nsIdleServiceGonk.cpp', - 'nsLookAndFeel.cpp', - 'nsScreenManagerGonk.cpp', - 'nsWidgetFactory.cpp', - 'nsWindow.cpp', - 'OrientationObserver.cpp', - 'ProcessOrientation.cpp', - 'WidgetTraceEvent.cpp' -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/dom/system/android', - '/gfx/skia/skia/include/config', - '/gfx/skia/skia/include/core', - '/image', - '/widget', -] - -DEFINES['HAVE_OFF64_T'] = True -DEFINES['SK_BUILD_FOR_ANDROID_NDK'] = True -DEFINES['HAVE_POSIX_CLOCKS'] = True - -LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include', - 'hardware/libhardware/include', - 'hardware/libhardware_legacy/include', - ] -] diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp b/widget/gonk/nativewindow/FakeSurfaceComposer.cpp deleted file mode 100644 index 7e4a2a9d8..000000000 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "FakeSurfaceComposer" -//#define LOG_NDEBUG 0 - -#include <stdint.h> -#include <sys/types.h> -#include <errno.h> -#include <cutils/atomic.h> -#include <cutils/log.h> -#include <cutils/properties.h> -#include <private/android_filesystem_config.h> - -#include <gui/IDisplayEventConnection.h> -#include <gui/GraphicBufferAlloc.h> -#include <gui/Surface.h> -#include <ui/DisplayInfo.h> - -#if ANDROID_VERSION >= 21 -#include <ui/Rect.h> -#endif - -#include "../libdisplay/GonkDisplay.h" -#include "../nsScreenManagerGonk.h" -#include "FakeSurfaceComposer.h" -#include "gfxPrefs.h" -#include "MainThreadUtils.h" -#include "mozilla/Assertions.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/CompositorThread.h" -#include "nsProxyRelease.h" -#include "nsThreadUtils.h" - -using namespace mozilla; - -namespace android { - -/* static */ -void FakeSurfaceComposer::instantiate() { - defaultServiceManager()->addService( - String16("SurfaceFlinger"), new FakeSurfaceComposer()); -} - -FakeSurfaceComposer::FakeSurfaceComposer() - : BnSurfaceComposer() -{ -} - -FakeSurfaceComposer::~FakeSurfaceComposer() -{ -} - -status_t FakeSurfaceComposer::onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) -{ - switch (code) { - case CREATE_CONNECTION: - case CREATE_DISPLAY: - case SET_TRANSACTION_STATE: - case CAPTURE_SCREEN: - { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - // Accept request only when uid is root. - if (uid != AID_ROOT) { - ALOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - break; - } - } - - return BnSurfaceComposer::onTransact(code, data, reply, flags); -} - -sp<ISurfaceComposerClient> FakeSurfaceComposer::createConnection() -{ - return nullptr; -} - -sp<IGraphicBufferAlloc> FakeSurfaceComposer::createGraphicBufferAlloc() -{ - sp<GraphicBufferAlloc> gba(new GraphicBufferAlloc()); - return gba; -} - -class DestroyDisplayRunnable : public Runnable { -public: - DestroyDisplayRunnable(FakeSurfaceComposer* aComposer, ssize_t aIndex) - : mComposer(aComposer), mIndex(aIndex) { } - NS_IMETHOD Run() override { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - Mutex::Autolock _l(mComposer->mStateLock); - RefPtr<nsScreenManagerGonk> screenManager = - nsScreenManagerGonk::GetInstance(); - screenManager->RemoveScreen(GonkDisplay::DISPLAY_VIRTUAL); - mComposer->mDisplays.removeItemsAt(mIndex); - return NS_OK; - } - sp<FakeSurfaceComposer> mComposer; - ssize_t mIndex; -}; - -sp<IBinder> FakeSurfaceComposer::createDisplay(const String8& displayName, - bool secure) -{ -#if ANDROID_VERSION >= 19 - class DisplayToken : public BBinder { - sp<FakeSurfaceComposer> composer; - virtual ~DisplayToken() { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - // no more references, this display must be terminated - Mutex::Autolock _l(composer->mStateLock); - ssize_t idx = composer->mDisplays.indexOfKey(this); - if (idx >= 0) { - nsCOMPtr<nsIRunnable> task(new DestroyDisplayRunnable(composer.get(), idx)); - NS_DispatchToMainThread(task); - } - } - public: - DisplayToken(const sp<FakeSurfaceComposer>& composer) - : composer(composer) { - } - }; - - sp<BBinder> token = new DisplayToken(this); - - Mutex::Autolock _l(mStateLock); - DisplayDeviceState info(HWC_DISPLAY_VIRTUAL); - info.displayName = displayName; - info.displayId = GonkDisplay::DISPLAY_VIRTUAL; - info.isSecure = secure; - mDisplays.add(token, info); - return token; -#else - return nullptr; -#endif -} - -#if ANDROID_VERSION >= 19 -void FakeSurfaceComposer::destroyDisplay(const sp<IBinder>& display) -{ - Mutex::Autolock _l(mStateLock); - - ssize_t idx = mDisplays.indexOfKey(display); - if (idx < 0) { - ALOGW("destroyDisplay: invalid display token"); - return; - } - - nsCOMPtr<nsIRunnable> task(new DestroyDisplayRunnable(this, idx)); - NS_DispatchToMainThread(task); -} -#endif - -sp<IBinder> FakeSurfaceComposer::getBuiltInDisplay(int32_t id) -{ - // support only primary display - if (uint32_t(id) != HWC_DISPLAY_PRIMARY) { - return NULL; - } - - if (!mPrimaryDisplay.get()) { - mPrimaryDisplay = new BBinder(); - } - return mPrimaryDisplay; -} - -void FakeSurfaceComposer::setTransactionState( - const Vector<ComposerState>& state, - const Vector<DisplayState>& displays, - uint32_t flags) -{ - Mutex::Autolock _l(mStateLock); - size_t count = displays.size(); - for (size_t i=0 ; i<count ; i++) { - const DisplayState& s(displays[i]); - setDisplayStateLocked(s); - } -} - -uint32_t FakeSurfaceComposer::setDisplayStateLocked(const DisplayState& s) -{ - ssize_t dpyIdx = mDisplays.indexOfKey(s.token); - if (dpyIdx < 0) { - return 0; - } - - uint32_t flags = 0; - DisplayDeviceState& disp(mDisplays.editValueAt(dpyIdx)); - - if (!disp.isValid()) { - return 0; - } - - const uint32_t what = s.what; - if (what & DisplayState::eSurfaceChanged) { - if (disp.surface->asBinder() != s.surface->asBinder()) { - disp.surface = s.surface; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eLayerStackChanged) { - if (disp.layerStack != s.layerStack) { - disp.layerStack = s.layerStack; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eDisplayProjectionChanged) { - if (disp.orientation != s.orientation) { - disp.orientation = s.orientation; - flags |= eDisplayTransactionNeeded; - } - if (disp.frame != s.frame) { - disp.frame = s.frame; - flags |= eDisplayTransactionNeeded; - } - if (disp.viewport != s.viewport) { - disp.viewport = s.viewport; - flags |= eDisplayTransactionNeeded; - } - } -#if ANDROID_VERSION >= 21 - if (what & DisplayState::eDisplaySizeChanged) { - if (disp.width != s.width) { - disp.width = s.width; - flags |= eDisplayTransactionNeeded; - } - if (disp.height != s.height) { - disp.height = s.height; - flags |= eDisplayTransactionNeeded; - } - } -#endif - - if (what & DisplayState::eSurfaceChanged) { - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([&]() { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->AddScreen(GonkDisplay::DISPLAY_VIRTUAL, disp.surface.get()); - }); - NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); - } - - return flags; -} - -void FakeSurfaceComposer::bootFinished() -{ -} - -bool FakeSurfaceComposer::authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const { - return false; -} - -sp<IDisplayEventConnection> FakeSurfaceComposer::createDisplayEventConnection() { - return nullptr; -} - -// --------------------------------------------------------------------------- -// Capture screen into an IGraphiBufferProducer -// --------------------------------------------------------------------------- - -class Barrier { -public: - inline Barrier() : state(CLOSED) { } - inline ~Barrier() { } - - // Release any threads waiting at the Barrier. - // Provides release semantics: preceding loads and stores will be visible - // to other threads before they wake up. - void open() { - Mutex::Autolock _l(lock); - state = OPENED; - cv.broadcast(); - } - - // Reset the Barrier, so wait() will block until open() has been called. - void close() { - Mutex::Autolock _l(lock); - state = CLOSED; - } - - // Wait until the Barrier is OPEN. - // Provides acquire semantics: no subsequent loads or stores will occur - // until wait() returns. - void wait() const { - Mutex::Autolock _l(lock); - while (state == CLOSED) { - cv.wait(lock); - } - } -private: - enum { OPENED, CLOSED }; - mutable Mutex lock; - mutable Condition cv; - volatile int state; -}; - -/* The code below is here to handle b/8734824 - * - * We create a IGraphicBufferProducer wrapper that forwards all calls - * to the calling binder thread, where they are executed. This allows - * the calling thread to be reused (on the other side) and not - * depend on having "enough" binder threads to handle the requests. - * - */ - -class GraphicProducerWrapper : public BBinder, public MessageHandler { - sp<IGraphicBufferProducer> impl; - sp<Looper> looper; - status_t result; - bool exitPending; - bool exitRequested; - mutable Barrier barrier; - volatile int32_t memoryBarrier; - uint32_t code; - Parcel const* data; - Parcel* reply; - - enum { - MSG_API_CALL, - MSG_EXIT - }; - - /* - * this is called by our "fake" BpGraphicBufferProducer. We package the - * data and reply Parcel and forward them to the calling thread. - */ - virtual status_t transact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t flags) { - this->code = code; - this->data = &data; - this->reply = reply; - android_atomic_acquire_store(0, &memoryBarrier); - if (exitPending) { - // if we've exited, we run the message synchronously right here - handleMessage(Message(MSG_API_CALL)); - } else { - barrier.close(); - looper->sendMessage(this, Message(MSG_API_CALL)); - barrier.wait(); - } - return NO_ERROR; - } - - /* - * here we run on the binder calling thread. All we've got to do is - * call the real BpGraphicBufferProducer. - */ - virtual void handleMessage(const Message& message) { - android_atomic_release_load(&memoryBarrier); - if (message.what == MSG_API_CALL) { - impl->asBinder()->transact(code, data[0], reply); - barrier.open(); - } else if (message.what == MSG_EXIT) { - exitRequested = true; - } - } - -public: - GraphicProducerWrapper(const sp<IGraphicBufferProducer>& impl) : - impl(impl), looper(new Looper(true)), result(NO_ERROR), - exitPending(false), exitRequested(false) { - } - - status_t waitForResponse() { - do { - looper->pollOnce(-1); - } while (!exitRequested); - return result; - } - - void exit(status_t result) { - this->result = result; - exitPending = true; - looper->sendMessage(this, Message(MSG_EXIT)); - } -}; - -status_t -FakeSurfaceComposer::captureScreen(const sp<IBinder>& display - , const sp<IGraphicBufferProducer>& producer -#if ANDROID_VERSION >= 21 - , Rect sourceCrop -#endif - , uint32_t reqWidth - , uint32_t reqHeight - , uint32_t minLayerZ - , uint32_t maxLayerZ -#if ANDROID_VERSION >= 21 - , bool useIdentityTransform - , Rotation rotation -#elif ANDROID_VERSION < 19 - , bool isCpuConsumer -#endif - ) -{ - if (display == 0 || producer == 0) { - return BAD_VALUE; - } - - // Limit only to primary display - if (display != mPrimaryDisplay) { - return BAD_VALUE; - } - - // this creates a "fake" BBinder which will serve as a "fake" remote - // binder to receive the marshaled calls and forward them to the - // real remote (a BpGraphicBufferProducer) - sp<GraphicProducerWrapper> wrapper = new GraphicProducerWrapper(producer); - // the asInterface() call below creates our "fake" BpGraphicBufferProducer - // which does the marshaling work forwards to our "fake remote" above. - sp<IGraphicBufferProducer> fakeProducer = IGraphicBufferProducer::asInterface(wrapper); - - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([&]() { - captureScreenImp(fakeProducer, reqWidth, reqHeight, wrapper.get()); - }); - NS_DispatchToMainThread(runnable); - - status_t result = wrapper->waitForResponse(); - - return result; -} - -class RunnableCallTask final : public Runnable -{ -public: - explicit RunnableCallTask(nsIRunnable* aRunnable) - : mRunnable(aRunnable) {} - - NS_IMETHOD Run() override - { - return mRunnable->Run(); - } -protected: - nsCOMPtr<nsIRunnable> mRunnable; -}; - -void -FakeSurfaceComposer::captureScreenImp(const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, - uint32_t reqHeight, - const sp<GraphicProducerWrapper>& wrapper) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(wrapper.get()); - - RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); - - // get screen geometry - nsIntRect screenBounds = screen->GetNaturalBounds().ToUnknownRect(); - const uint32_t hw_w = screenBounds.width; - const uint32_t hw_h = screenBounds.height; - - if (reqWidth > hw_w || reqHeight > hw_h) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(BAD_VALUE); - return; - } - - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; - - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([screen, reqWidth, reqHeight, producer, wrapper]() { - // create a surface (because we're a producer, and we need to - // dequeue/queue a buffer) - sp<Surface> sur = new Surface(producer); - ANativeWindow* window = sur.get(); - // The closure makes screen const and we can't call forget() on it. - RefPtr<nsScreenGonk> screenAlias = screen; - - if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != NO_ERROR) { - static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(BAD_VALUE); - NS_ReleaseOnMainThread(screenAlias.forget()); - return; - } - uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - - int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); - err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, usage); - - status_t result = NO_ERROR; - if (err == NO_ERROR) { - ANativeWindowBuffer* buffer; - result = native_window_dequeue_buffer_and_wait(window, &buffer); - if (result == NO_ERROR) { - nsresult rv = screen->MakeSnapshot(buffer); - if (rv != NS_OK) { - result = INVALID_OPERATION; - } - window->queueBuffer(window, buffer, -1); - } - } else { - result = BAD_VALUE; - } - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - static_cast<GraphicProducerWrapper*>(producer->asBinder().get())->exit(result); - NS_ReleaseOnMainThread(screenAlias.forget()); - }); - - layers::CompositorThreadHolder::Loop()->PostTask( - MakeAndAddRef<RunnableCallTask>(runnable)); -} - -#if ANDROID_VERSION >= 21 -void -FakeSurfaceComposer::setPowerMode(const sp<IBinder>& display, int mode) -{ -} - -status_t -FakeSurfaceComposer::getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs) -{ - if (configs == NULL) { - return BAD_VALUE; - } - - // Limit DisplayConfigs only to primary display - if (!display.get() || display != mPrimaryDisplay) { - return NAME_NOT_FOUND; - } - - configs->clear(); - DisplayInfo info = DisplayInfo(); - - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([&]() { - MOZ_ASSERT(NS_IsMainThread()); - getPrimaryDisplayInfo(&info); - }); - NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); - - configs->push_back(info); - return NO_ERROR; -} - -status_t -FakeSurfaceComposer::getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats) -{ - return INVALID_OPERATION; -} - -int -FakeSurfaceComposer::getActiveConfig(const sp<IBinder>& display) -{ - // Only support primary display. - if (display.get() && (display == mPrimaryDisplay)) { - return 0; - } - return INVALID_OPERATION; -} - -status_t -FakeSurfaceComposer::setActiveConfig(const sp<IBinder>& display, int id) -{ - return INVALID_OPERATION; -} - -status_t -FakeSurfaceComposer::clearAnimationFrameStats() -{ - return INVALID_OPERATION; -} - -status_t -FakeSurfaceComposer::getAnimationFrameStats(FrameStats* outStats) const -{ - return INVALID_OPERATION; -} -#else -void -FakeSurfaceComposer::blank(const sp<IBinder>& display) -{ -} - -void -FakeSurfaceComposer::unblank(const sp<IBinder>& display) -{ -} - -status_t -FakeSurfaceComposer::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) -{ - if (info == NULL) { - return BAD_VALUE; - } - - // Limit DisplayConfigs only to primary display - if (!display.get() || display != mPrimaryDisplay) { - return NAME_NOT_FOUND; - } - - nsCOMPtr<nsIRunnable> runnable = - NS_NewRunnableFunction([&]() { - MOZ_ASSERT(NS_IsMainThread()); - getPrimaryDisplayInfo(info); - }); - NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); - - return NO_ERROR; -} -#endif - -#define VSYNC_EVENT_PHASE_OFFSET_NS 0 -#define SF_VSYNC_EVENT_PHASE_OFFSET_NS 0 - -void -FakeSurfaceComposer::getPrimaryDisplayInfo(DisplayInfo* info) -{ - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - - // Implementation mimic android SurfaceFlinger::getDisplayConfigs(). - - class Density { - static int getDensityFromProperty(char const* propName) { - char property[PROPERTY_VALUE_MAX]; - int density = 0; - if (property_get(propName, property, NULL) > 0) { - density = atoi(property); - } - return density; - } - public: - static int getEmuDensity() { - return getDensityFromProperty("qemu.sf.lcd_density"); } - static int getBuildDensity() { - return getDensityFromProperty("ro.sf.lcd_density"); } - }; - - RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); - - float xdpi = screen->GetDpi(); - float ydpi = screen->GetDpi(); - int fps = 60; // XXX set a value from hwc hal - nsIntRect screenBounds = screen->GetNaturalBounds().ToUnknownRect(); - - // The density of the device is provided by a build property - float density = Density::getBuildDensity() / 160.0f; - if (density == 0) { - // the build doesn't provide a density -- this is wrong! - // use xdpi instead - ALOGE("ro.sf.lcd_density must be defined as a build property"); - density = xdpi / 160.0f; - } - info->density = density; - info->orientation = screen->EffectiveScreenRotation(); - - info->w = screenBounds.width; - info->h = screenBounds.height; - info->xdpi = xdpi; - info->ydpi = ydpi; - info->fps = fps; -#if ANDROID_VERSION >= 21 - info->appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS; - - // This is how far in advance a buffer must be queued for - // presentation at a given time. If you want a buffer to appear - // on the screen at time N, you must submit the buffer before - // (N - presentationDeadline). - // - // Normally it's one full refresh period (to give SF a chance to - // latch the buffer), but this can be reduced by configuring a - // DispSync offset. Any additional delays introduced by the hardware - // composer or panel must be accounted for here. - // - // We add an additional 1ms to allow for processing time and - // differences between the ideal and actual refresh rate. - info->presentationDeadline = - (1e9 / fps) - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000; -#endif - // All non-virtual displays are currently considered secure. - info->secure = true; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.h b/widget/gonk/nativewindow/FakeSurfaceComposer.h deleted file mode 100644 index 97a717444..000000000 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_FAKE_SURFACE_COMPOSER_H -#define NATIVEWINDOW_FAKE_SURFACE_COMPOSER_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Looper.h> - -#include <binder/BinderService.h> - -#include <gui/IGraphicBufferProducer.h> -#include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> -#include <hardware/hwcomposer.h> -#include <private/gui/LayerState.h> -#include <utils/KeyedVector.h> - -class nsIWidget; - -namespace android { - -// --------------------------------------------------------------------------- - -class GraphicProducerWrapper; -class IGraphicBufferAlloc; - -enum { - eTransactionNeeded = 0x01, - eTraversalNeeded = 0x02, - eDisplayTransactionNeeded = 0x04, - eTransactionMask = 0x07 -}; - -class FakeSurfaceComposer : public BinderService<FakeSurfaceComposer>, - public BnSurfaceComposer -{ -public: - static char const* getServiceName() { - return "FakeSurfaceComposer"; - } - - // Instantiate FakeSurfaceComposer and register to service manager. - // If service manager is not present, wait until service manager becomes present. - static void instantiate(); - -#if ANDROID_VERSION >= 19 - virtual void destroyDisplay(const sp<android::IBinder>& display); -#endif - -#if ANDROID_VERSION >= 21 - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, - bool useIdentityTransform, - Rotation rotation = eRotateNone); -#elif ANDROID_VERSION >= 19 - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); -#else - virtual status_t captureScreen(const sp<IBinder>& display, - const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer); -#endif - -private: - FakeSurfaceComposer(); - // We're reference counted, never destroy FakeSurfaceComposer directly - virtual ~FakeSurfaceComposer(); - - /* ------------------------------------------------------------------------ - * IBinder interface - */ - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags); - - /* ------------------------------------------------------------------------ - * ISurfaceComposer interface - */ - virtual sp<ISurfaceComposerClient> createConnection(); - virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc(); - virtual sp<IBinder> createDisplay(const String8& displayName, bool secure); - virtual sp<IBinder> getBuiltInDisplay(int32_t id); - virtual void setTransactionState(const Vector<ComposerState>& state, - const Vector<DisplayState>& displays, uint32_t flags); - virtual void bootFinished(); - virtual bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const; - virtual sp<IDisplayEventConnection> createDisplayEventConnection(); -#if ANDROID_VERSION >= 21 - virtual void setPowerMode(const sp<IBinder>& display, int mode); - virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayInfo>* configs); - virtual status_t getDisplayStats(const sp<IBinder>& display, DisplayStatInfo* stats); - virtual int getActiveConfig(const sp<IBinder>& display); - virtual status_t setActiveConfig(const sp<IBinder>& display, int id); - virtual status_t clearAnimationFrameStats(); - virtual status_t getAnimationFrameStats(FrameStats* outStats) const; -#elif ANDROID_VERSION >= 17 - // called when screen needs to turn off - virtual void blank(const sp<IBinder>& display); - // called when screen is turning back on - virtual void unblank(const sp<IBinder>& display); - virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info); -#endif - void getPrimaryDisplayInfo(DisplayInfo* info); - - /* ------------------------------------------------------------------------ - * Transactions - */ - uint32_t setDisplayStateLocked(const DisplayState& s); - - void captureScreenImp(const sp<IGraphicBufferProducer>& producer, - uint32_t reqWidth, - uint32_t reqHeight, - const sp<GraphicProducerWrapper>& wrapper); - - sp<IBinder> mPrimaryDisplay; - - struct DisplayDeviceState { - enum { - NO_LAYER_STACK = 0xFFFFFFFF, - }; - DisplayDeviceState() - : type(-1), displayId(-1), width(0), height(0) { - } - DisplayDeviceState(int type) - : type(type), displayId(-1), layerStack(NO_LAYER_STACK), orientation(0), width(0), height(0) { - viewport.makeInvalid(); - frame.makeInvalid(); - } - bool isValid() const { return type >= 0; } - int type; - int displayId; - sp<IGraphicBufferProducer> surface; - uint32_t layerStack; - Rect viewport; - Rect frame; - uint8_t orientation; - uint32_t width, height; - String8 displayName; - bool isSecure; - }; - - // access must be protected by mStateLock - mutable Mutex mStateLock; - DefaultKeyedVector<wp<IBinder>, DisplayDeviceState> mDisplays; - - friend class DestroyDisplayRunnable; -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_FAKE_SURFACE_COMPOSER_H diff --git a/widget/gonk/nativewindow/GonkBufferQueue.h b/widget/gonk/nativewindow/GonkBufferQueue.h deleted file mode 100644 index defdb0ae2..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueue.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "GonkBufferQueueLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "GonkBufferQueueKK.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 -# include "GonkBufferQueueJB.h" -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp deleted file mode 100644 index 81502f81e..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp +++ /dev/null @@ -1,1036 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include <utils/Log.h> - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" - -#include "GonkBufferQueueJB.h" - -// Macros for including the GonkBufferQueue name in log messages -#define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - -#define ATRACE_BUFFER_INDEX(index) - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -static const char* scalingModeName(int scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode, - const sp<IGraphicBufferAlloc>& allocator) : - mDefaultWidth(1), - mDefaultHeight(1), - mMaxAcquiredBufferCount(1), - mDefaultMaxBufferCount(2), - mOverrideMaxBufferCount(0), - mSynchronousMode(true), - mAllowSynchronousMode(allowSynchronousMode), - mConnectedApi(NO_CONNECTED_API), - mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mConsumerUsageBits(0), - mTransformHint(0) -{ - // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - ST_LOGV("GonkBufferQueue"); -} - -GonkBufferQueue::~GonkBufferQueue() { - ST_LOGV("~GonkBufferQueue"); -} - -status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) { - if (count < 2 || count > NUM_BUFFER_SLOTS) - return BAD_VALUE; - - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -bool GonkBufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - -void GonkBufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock lock(mMutex); - mDefaultBufferFormat = defaultFormat; - return NO_ERROR; -} - -status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) { - Mutex::Autolock lock(mMutex); - mConsumerUsageBits = usage; - return NO_ERROR; -} - -status_t GonkBufferQueue::setTransformHint(uint32_t hint) { - ST_LOGV("setTransformHint: %02x", hint); - Mutex::Autolock lock(mMutex); - mTransformHint = hint; - return NO_ERROR; -} - -already_AddRefed<TextureClient> -GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) -{ - Mutex::Autolock _l(mMutex); - if (buffer == NULL) { - ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return nullptr; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { - RefPtr<TextureClient> client(mSlots[i].mTextureClient); - return client.forget(); - } - } - ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return nullptr; -} - -int GonkBufferQueue::getSlotFromTextureClientLocked( - TextureClient* client) const -{ - if (client == NULL) { - ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return BAD_VALUE; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mTextureClient == client) { - return i; - } - } - ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); - return BAD_VALUE; -} - - -status_t GonkBufferQueue::setBufferCount(int bufferCount) { - ST_LOGV("setBufferCount: count=%d", bufferCount); - - sp<ConsumerListener> listener; - { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (bufferCount > NUM_BUFFER_SLOTS) { - ST_LOGE("setBufferCount: bufferCount too large (max %d)", - NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - // Error out if the user has dequeued buffers - int maxBufferCount = getMaxBufferCountLocked(); - for (int i=0 ; i<maxBufferCount; i++) { - if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { - ST_LOGE("setBufferCount: client owns some buffers"); - return -EINVAL; - } - } - - const int minBufferSlots = getMinMaxBufferCountLocked(); - if (bufferCount == 0) { - mOverrideMaxBufferCount = 0; - mDequeueCondition.broadcast(); - return NO_ERROR; - } - - if (bufferCount < minBufferSlots) { - ST_LOGE("setBufferCount: requested buffer count (%d) is less than " - "minimum (%d)", bufferCount, minBufferSlots); - return BAD_VALUE; - } - - // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. - // - // XXX: Should this use drainQueueAndFreeBuffersLocked instead? - freeAllBuffersLocked(); - mOverrideMaxBufferCount = bufferCount; - mBufferHasBeenQueued = false; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } // scope for lock - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return NO_ERROR; -} - -int GonkBufferQueue::query(int what, int* outValue) -{ - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("query: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mDefaultBufferFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = getMinUndequeuedBufferCountLocked(); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mQueue.size() >= 2); - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - -status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { - ST_LOGV("requestBuffer: slot=%d", slot); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - int maxBufferCount = getMaxBufferCountLocked(); - if (slot < 0 || maxBufferCount <= slot) { - ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, slot); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - // XXX: I vaguely recall there was some reason this can be valid, but - // for the life of me I can't recall under what circumstances that's - // the case. - ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", - slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); - - if ((w && !h) || (!w && h)) { - ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); - return BAD_VALUE; - } - - status_t returnFlags(OK); - int buf = INVALID_BUFFER_SLOT; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (format == 0) { - format = mDefaultBufferFormat; - } - // turn on usage bits the consumer requested - usage |= mConsumerUsageBits; - - int found = -1; - int dequeuedCount = 0; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - const int maxBufferCount = getMaxBufferCountLocked(); - - // Free up any buffers that are in slots beyond the max buffer - // count. - //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - // assert(mSlots[i].mBufferState == BufferSlot::FREE); - // if (mSlots[i].mGraphicBuffer != NULL) { - // freeBufferLocked(i); - // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; - // } - //} - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - dequeuedCount = 0; - for (int i = 0; i < maxBufferCount; i++) { - const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; - } - - if (state == BufferSlot::FREE) { - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - if ((found < 0) || - mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { - found = i; - } - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mOverrideMaxBufferCount && dequeuedCount) { - ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below. - if (mBufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); - if (newUndequeuedCount < minUndequeuedCount) { - ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " - "exceeded (dequeued=%d undequeudCount=%d)", - minUndequeuedCount, dequeuedCount, - newUndequeuedCount); - return -EBUSY; - } - } - - // If no buffer is found, wait for a buffer to be released or for - // the max buffer count to change. - tryAgain = found == INVALID_BUFFER_SLOT; - if (tryAgain) { - mDequeueCondition.wait(mMutex); - } - } - - - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ST_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - buf = found; - *outBuf = found; - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - mSlots[buf].mAcquireCalled = false; - mSlots[buf].mGraphicBuffer = NULL; - mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = Fence::NO_FENCE; - if (mSlots[buf].mTextureClient) { - mSlots[buf].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr<TextureClientReleaseTask> task = - MakeAndAddRef<TextureClientReleaseTask>(mSlots[buf].mTextureClient); - mSlots[buf].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; - } - - *outFence = mSlots[buf].mFence; - mSlots[buf].mFence = Fence::NO_FENCE; - } // end lock scope - - sp<GraphicBuffer> graphicBuffer; - if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - RefPtr<LayersIPCChannel> allocator = ImageBridgeChild::GetSingleton(); - GrallocTextureData* texData = GrallocTextureData::Create(IntSize(w,h), format, - gfx::BackendType::NONE, usage, - allocator); - if (!texData) { - ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); - return -ENOMEM; - } - RefPtr<TextureClient> textureClient = new TextureClient(texData, TextureFlags::RECYCLE | TextureFlags::DEALLOCATE_CLIENT, allocator); - sp<GraphicBuffer> graphicBuffer = texData->GetGraphicBuffer(); - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - mSlots[buf].mGraphicBuffer = graphicBuffer; - mSlots[buf].mTextureClient = textureClient; - ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, - mSlots[buf].mGraphicBuffer->handle); - //mSlots[*outBuf].mGraphicBuffer = graphicBuffer; - } - } - - ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, - mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t GonkBufferQueue::setSynchronousMode(bool enabled) { - ST_LOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mSynchronousMode != enabled) { - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return OK; -} - -status_t GonkBufferQueue::queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output) { - - Rect crop; - uint32_t transform; - int scalingMode; - int64_t timestamp; - sp<Fence> fence; - - input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); - -#if ANDROID_VERSION >= 18 - if (fence == NULL) { - ST_LOGE("queueBuffer: fence is NULL"); - return BAD_VALUE; - } -#endif - - ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " - "scale=%s", - buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - sp<ConsumerListener> listener; - - { // scope for the lock - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - int maxBufferCount = getMaxBufferCountLocked(); - if (buf < 0 || buf >= maxBufferCount) { - ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); - return -EINVAL; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("queueBuffer: slot %d is not owned by the client " - "(state=%d)", buf, mSlots[buf].mBufferState); - return -EINVAL; - } else if (!mSlots[buf].mRequestBufferCalled) { - ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", buf); - return -EINVAL; - } - - const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedCrop; - crop.intersect(bufferRect, &croppedCrop); - if (croppedCrop != crop) { - ST_LOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", buf); - return -EINVAL; - } - - if (mSynchronousMode) { - // In synchronous mode we queue all buffers in a FIFO. - mQueue.push_back(buf); - } else { - // In asynchronous mode we only keep the most recent buffer. - if (mQueue.empty()) { - mQueue.push_back(buf); - } else { - Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; - // and we record the new buffer index in the queued list - *front = buf; - } - } - // always signals that an additional frame should be consumed - // to handle max acquired buffer count reached case. - listener = mConsumerListener; - - mSlots[buf].mTimestamp = timestamp; - mSlots[buf].mCrop = crop; - mSlots[buf].mTransform = transform; - mSlots[buf].mFence = fence; - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode); - scalingMode = mSlots[buf].mScalingMode; - break; - } - - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mSlots[buf].mScalingMode = scalingMode; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - - mBufferHasBeenQueued = true; - mDequeueCondition.broadcast(); - - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - } // scope for the lock - - // call back without lock held - if (listener != 0) { - listener->onFrameAvailable(); - } - return NO_ERROR; -} - -#if ANDROID_VERSION == 17 -void GonkBufferQueue::cancelBuffer(int buf, sp<Fence> fence) { -#else -void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) { -#endif - - ST_LOGV("cancelBuffer: slot=%d", buf); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!"); - return; - } - - int maxBufferCount = getMaxBufferCountLocked(); - if (buf < 0 || buf >= maxBufferCount) { - ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); - return; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - buf, mSlots[buf].mBufferState); - return; -#if ANDROID_VERSION >= 18 - } else if (fence == NULL) { - ST_LOGE("cancelBuffer: fence is NULL"); - return; -#endif - } - mSlots[buf].mBufferState = BufferSlot::FREE; - mSlots[buf].mFrameNumber = 0; - mSlots[buf].mFence = fence; - mDequeueCondition.broadcast(); -} - -status_t GonkBufferQueue::connect(int api, QueueBufferOutput* output) { - ST_LOGV("connect: api=%d", api); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("connect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mConsumerListener == NULL) { - ST_LOGE("connect: GonkBufferQueue has no consumer!"); - return NO_INIT; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi != NO_CONNECTED_API) { - ST_LOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } else { - mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - } - break; - default: - err = -EINVAL; - break; - } - - mBufferHasBeenQueued = false; - - return err; -} - -status_t GonkBufferQueue::disconnect(int api) { - ST_LOGV("disconnect: api=%d", api); - - int err = NO_ERROR; - sp<ConsumerListener> listener; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // it is not really an error to disconnect after the surface - // has been abandoned, it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - freeAllBuffersLocked(); - mConnectedApi = NO_CONNECTED_API; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } else { - ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } - break; - default: - ST_LOGE("disconnect: unknown API %d", api); - err = -EINVAL; - break; - } - } - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return err; -} - -void GonkBufferQueue::dumpToString(String8& result) const -{ - char buffer[1024]; - GonkBufferQueue::dumpToString(result, "", buffer, 1024); -} - -void GonkBufferQueue::dumpToString(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } - - int maxBufferCount = getMaxBufferCountLocked(); - - snprintf(buffer, SIZE, - "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mDefaultBufferFormat, mTransformHint, - fifoSize, fifo.string()); - result.append(buffer); - - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - for (int i=0 ; i<maxBufferCount ; i++) { - const BufferSlot& slot(mSlots[i]); - snprintf(buffer, SIZE, - "%s%s[%02d] " - "state=%-8s, crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#llx, scale=%s", - prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp, - scalingModeName(slot.mScalingMode) - ); - result.append(buffer); - - const sp<GraphicBuffer>& buf(slot.mGraphicBuffer); - if (buf != NULL) { - snprintf(buffer, SIZE, - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - result.append(buffer); - } - result.append("\n"); - } -} - -void GonkBufferQueue::freeAllBuffersLocked() -{ - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].mGraphicBuffer = 0; - if (mSlots[i].mTextureClient) { - mSlots[i].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr<TextureClientReleaseTask> task = - MakeAndAddRef<TextureClientReleaseTask>(mSlots[i].mTextureClient); - mSlots[i].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - mSlots[i].mNeedsCleanupOnRelease = true; - } - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - // destroy fence as GonkBufferQueue now takes ownership - mSlots[i].mFence = Fence::NO_FENCE; - } -} - -status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer) { - Mutex::Autolock _l(mMutex); - - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer, so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - numAcquiredBuffers++; - } - } - if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) { - ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)", - numAcquiredBuffers, mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = *front; - - // In android, when the buffer is aquired by BufferConsumer, - // BufferQueue releases a reference to the buffer and - // it's ownership moves to the BufferConsumer. - // In b2g, GonkBufferQueue continues to have a buffer ownership. - // It is necessary to free buffer via ImageBridgeChild. - - //if (mSlots[buf].mAcquireCalled) { - // buffer->mGraphicBuffer = NULL; - //} else { - // buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - //} - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mTimestamp = mSlots[buf].mTimestamp; - buffer->mBuf = buf; - buffer->mFence = mSlots[buf].mFence; - - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; - - mQueue.erase(front); - mDequeueCondition.broadcast(); - } else { - return NO_BUFFER_AVAILABLE; - } - - return NO_ERROR; -} - -status_t GonkBufferQueue::releaseBuffer(int buf, const sp<Fence>& fence) { - Mutex::Autolock _l(mMutex); - -#if ANDROID_VERSION == 17 - if (buf == INVALID_BUFFER_SLOT) { -#else - if (buf == INVALID_BUFFER_SLOT || fence == NULL) { -#endif - return BAD_VALUE; - } - - mSlots[buf].mFence = fence; - - // The buffer can now only be released if its in the acquired state - if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mBufferState = BufferSlot::FREE; - } else if (mSlots[buf].mNeedsCleanupOnRelease) { - ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); - mSlots[buf].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); - return -EINVAL; - } - - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerConnect(const sp<ConsumerListener>& consumerListener) { - ST_LOGV("consumerConnect"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (consumerListener == NULL) { - ST_LOGE("consumerConnect: consumerListener may not be NULL"); - return BAD_VALUE; - } - - mConsumerListener = consumerListener; - - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerDisconnect() { - ST_LOGV("consumerDisconnect"); - Mutex::Autolock lock(mMutex); - - if (mConsumerListener == NULL) { - ST_LOGE("consumerDisconnect: No consumer is connected!"); - return -EINVAL; - } - - mAbandoned = true; - mConsumerListener = NULL; - mQueue.clear(); - freeAllBuffersLocked(); - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) { - ST_LOGV("getReleasedBuffers"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - uint32_t mask = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (!mSlots[i].mAcquireCalled) { - mask |= 1 << i; - } - } - *slotMask = mask; - - ST_LOGV("getReleasedBuffers: returning mask %#x", mask); - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) { - Mutex::Autolock lock(mMutex); - return setDefaultMaxBufferCountLocked(bufferCount); -} - -status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Mutex::Autolock lock(mMutex); - if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) { - ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - if (mConnectedApi != NO_CONNECTED_API) { - return INVALID_OPERATION; - } - mMaxAcquiredBufferCount = maxAcquiredBuffers; - return NO_ERROR; -} - -int GonkBufferQueue::getMinMaxBufferCountLocked() const { - return getMinUndequeuedBufferCountLocked() + 1; -} - -int GonkBufferQueue::getMinUndequeuedBufferCountLocked() const { - return mSynchronousMode ? mMaxAcquiredBufferCount : - mMaxAcquiredBufferCount + 1; -} - -int GonkBufferQueue::getMaxBufferCountLocked() const { - int minMaxBufferCount = getMinMaxBufferCountLocked(); - - int maxBufferCount = mDefaultMaxBufferCount; - if (maxBufferCount < minMaxBufferCount) { - maxBufferCount = minMaxBufferCount; - } - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } - - // Any buffers that are dequeued by the producer or sitting in the queue - // waiting to be consumed need to have their slots preserved. Such - // buffers will temporarily keep the max buffer count up until the slots - // no longer need to be preserved. - for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - BufferSlot::BufferState state = mSlots[i].mBufferState; - if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { - maxBufferCount = i + 1; - } - } - - return maxBufferCount; -} - -GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp<GonkBufferQueue::ConsumerListener>& consumerListener): - mConsumerListener(consumerListener) {} - -GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp<GonkBufferQueue::ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.h b/widget/gonk/nativewindow/GonkBufferQueueJB.h deleted file mode 100644 index df0c4599f..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueJB.h +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_JB_H -#define NATIVEWINDOW_GONKBUFFERQUEUE_JB_H - -#include <gui/IGraphicBufferAlloc.h> -#if ANDROID_VERSION == 17 -#include <gui/ISurfaceTexture.h> -#else -#include <gui/IGraphicBufferProducer.h> -#endif - -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> - -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -#include "mozilla/layers/LayersSurfaces.h" -#include "mozilla/layers/TextureClient.h" - -#if ANDROID_VERSION == 17 -#define IGraphicBufferProducer ISurfaceTexture -#endif - -namespace android { -// ---------------------------------------------------------------------------- - -#if ANDROID_VERSION == 17 -class GonkBufferQueue : public BnSurfaceTexture { -#else -class GonkBufferQueue : public BnGraphicBufferProducer { -#endif - typedef mozilla::layers::TextureClient TextureClient; - -public: - enum { MIN_UNDEQUEUED_BUFFERS = 2 }; - enum { NUM_BUFFER_SLOTS = 32 }; - enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; - enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE }; - - // When in async mode we reserve two slots in order to guarantee that the - // producer and consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - - // ConsumerListener is the interface through which the GonkBufferQueue notifies - // the consumer of events that the consumer may wish to react to. Because - // the consumer will generally have a mutex that is locked during calls from - // the consumer to the GonkBufferQueue, these calls from the GonkBufferQueue to the - // consumer *MUST* be called only when the GonkBufferQueue mutex is NOT locked. - struct ConsumerListener : public virtual RefBase { - // onFrameAvailable is called from queueBuffer each time an additional - // frame becomes available for consumption. This means that frames that - // are queued while in asynchronous mode only trigger the callback if no - // previous frames are pending. Frames queued while in synchronous mode - // always trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - - // onBuffersReleased is called to notify the buffer consumer that the - // GonkBufferQueue has released its references to one or more GraphicBuffers - // contained in its slots. The buffer consumer should then call - // GonkBufferQueue::getReleasedBuffers to retrieve the list of buffers - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onBuffersReleased() = 0; - }; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // GonkBufferQueue object and the consumer object. The reason this can't be a weak - // reference in the GonkBufferQueue class is because we're planning to expose the - // consumer side of a GonkBufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public GonkBufferQueue::ConsumerListener { - public: - - ProxyConsumerListener(const wp<GonkBufferQueue::ConsumerListener>& consumerListener); - virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - private: - - // mConsumerListener is a weak reference to the ConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp<GonkBufferQueue::ConsumerListener> mConsumerListener; - }; - - - // GonkBufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allowSynchronousMode specifies whether or not - // synchronous mode can be enabled by the producer. allocator is used to - // allocate all the needed gralloc buffers. - GonkBufferQueue(bool allowSynchronousMode = true, - const sp<IGraphicBufferAlloc>& allocator = NULL); - virtual ~GonkBufferQueue(); - - // Query native window attributes. The "what" values are enumerated in - // window.h (e.g. NATIVE_WINDOW_FORMAT). - virtual int query(int what, int* value); - - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the GonkBufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); - - // requestBuffer returns the GraphicBuffer for slot N. - // - // In normal operation, this is called the first time slot N is returned - // by dequeueBuffer. It must be called again if dequeueBuffer returns - // flags indicating that previously-returned buffers are no longer valid. - virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - - // dequeueBuffer gets the next buffer slot index for the producer to use. - // If a buffer slot is available then that slot index is written to the - // location pointed to by the buf argument and a status of OK is returned. - // If no slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // - // The fence parameter will be updated to hold the fence associated with - // the buffer. The contents of the buffer must not be overwritten until the - // fence signals. If the fence is Fence::NO_FENCE, the buffer may be - // written immediately. - // - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. If width and height are both zero, the - // default values specified by setDefaultBufferSize() are used instead. - // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. - // - // The usage argument specifies gralloc buffer usage flags. The values - // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These - // will be merged with the usage flags specified by setConsumerUsageBits. - // - // The return value may be a negative error value or a non-negative - // collection of flags. If the flags are set, the return values are - // valid, but additional actions must be performed. - // - // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the - // producer must discard cached GraphicBuffer references for the slot - // returned in buf. - // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer - // must discard cached GraphicBuffer references for all slots. - // - // In both cases, the producer will need to call requestBuffer to get a - // GraphicBuffer handle for the returned slot. -#if ANDROID_VERSION == 17 - virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { - return dequeueBuffer(buf, &fence, width, height, format, usage); - } -#endif - - virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); - - // queueBuffer returns a filled buffer to the GonkBufferQueue. - // - // Additional data is provided in the QueueBufferInput struct. Notably, - // a timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are producer-specific and should be documented by the - // producer. - // - // The caller may provide a fence that signals when all rendering - // operations have completed. Alternatively, NO_FENCE may be used, - // indicating that the buffer is ready immediately. - // - // Some values are returned in the output struct: the current settings - // for default width and height, the current transform hint, and the - // number of queued buffers. - virtual status_t queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output); - - // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't - // queue it for use by the consumer. - // - // The buffer will not be overwritten until the fence signals. The fence - // will usually be the one obtained from dequeueBuffer. -#if ANDROID_VERSION == 17 - virtual void cancelBuffer(int buf, sp<Fence> fence); -#else - virtual void cancelBuffer(int buf, const sp<Fence>& fence); -#endif - - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is synchronous. - // This should be called only during initialization. - virtual status_t setSynchronousMode(bool enabled); - - // connect attempts to connect a producer API to the GonkBufferQueue. This - // must be called before any other IGraphicBufferProducer methods are - // called except for getAllocator. A consumer must already be connected. - // - // This method will fail if connect was previously called on the - // GonkBufferQueue and no corresponding disconnect call was made (i.e. if - // it's still connected to a producer). - // - // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(int api, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer API from the GonkBufferQueue. - // Calling this method will cause any subsequent calls to other - // IGraphicBufferProducer methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the GonkBufferQueue is not currently - // connected to the specified producer API. - virtual status_t disconnect(int api); - - // dump our state in a String - virtual void dumpToString(String8& result) const; - virtual void dumpToString(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - - // public facing structure for BufferSlot - struct BufferItem { - - BufferItem() - : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { - mCrop.makeInvalid(); - } - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp<GraphicBuffer> mGraphicBuffer; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer - int mBuf; - - // mFence is a fence that will signal when the buffer is idle. - sp<Fence> mFence; - }; - - // The following public functions are the consumer-facing interface - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the GonkBufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - status_t acquireBuffer(BufferItem *buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // GonkBufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - status_t releaseBuffer(int buf, const sp<Fence>& releaseFence); - - // consumerConnect connects a consumer to the GonkBufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // GonkBufferQueue is placed into the "abandoned" state, causing most - // interactions with the GonkBufferQueue by the producer to fail. - // - // consumer may not be NULL. - status_t consumerConnect(const sp<ConsumerListener>& consumer); - - // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All - // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" - // state, causing most interactions with the GonkBufferQueue by the producer to - // fail. - status_t consumerDisconnect(); - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots have been released by the GonkBufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - status_t getReleasedBuffers(uint32_t* slotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - status_t setDefaultMaxBufferCount(int bufferCount); - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the GonkBufferQueue. - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - - // isSynchronousMode returns whether the GonkBufferQueue is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // setConsumerName sets the name used in logging - void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - status_t setTransformHint(uint32_t hint); - - already_AddRefed<TextureClient> getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - int getSlotFromTextureClientLocked(TextureClient* client) const; - -private: - // freeBufferLocked frees the GraphicBuffer and sync resources for the - // given slot. - //void freeBufferLocked(int index); - - // freeAllBuffersLocked frees the GraphicBuffer and sync resources for - // all slots. - //void freeAllBuffersLocked(); - void freeAllBuffersLocked(); - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - // The initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); - - // getMinBufferCountLocked returns the minimum number of buffers allowed - // given the current GonkBufferQueue state. - int getMinMaxBufferCountLocked() const; - - // getMinUndequeuedBufferCountLocked returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. - int getMinUndequeuedBufferCountLocked() const; - - // getMaxBufferCountLocked returns the maximum number of buffers that can - // be allocated at once. This value depends upon the following member - // variables: - // - // mSynchronousMode - // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // - // Any time one of these member variables is changed while a producer is - // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked() const; - - struct BufferSlot { - - BufferSlot() - : mBufferState(BufferSlot::FREE), - mRequestBufferCalled(false), - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false) { - mCrop.makeInvalid(); - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp<GraphicBuffer> mGraphicBuffer; - - // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. - RefPtr<TextureClient> mTextureClient; - - // BufferState represents the different states in which a buffer slot - // can be. All slots are initially FREE. - enum BufferState { - // FREE indicates that the buffer is available to be dequeued - // by the producer. The buffer may be in use by the consumer for - // a finite time, so the buffer must not be modified until the - // associated fence is signaled. - // - // The slot is "owned" by GonkBufferQueue. It transitions to DEQUEUED - // when dequeueBuffer is called. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // producer, but has not yet been queued or canceled. The - // producer may modify the buffer's contents as soon as the - // associated ready fence is signaled. - // - // The slot is "owned" by the producer. It can transition to - // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been filled by the - // producer and queued for use by the consumer. The buffer - // contents may continue to be modified for a finite time, so - // the contents must not be accessed until the associated fence - // is signaled. - // - // The slot is "owned" by GonkBufferQueue. It can transition to - // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is - // queued in asynchronous mode). - QUEUED = 2, - - // ACQUIRED indicates that the buffer has been acquired by the - // consumer. As with QUEUED, the contents must not be accessed - // by the consumer until the fence is signaled. - // - // The slot is "owned" by the consumer. It transitions to FREE - // when releaseBuffer is called. - ACQUIRED = 3 - }; - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the producer did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching producer bugs. - bool mRequestBufferCalled; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // (example: NATIVE_WINDOW_TRANSFORM_ROT_90) - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE) - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. This - // is used to dequeue buffers in LRU order (useful because buffers - // may be released before their release fence is signaled). - uint64_t mFrameNumber; - - // mEglFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a - // new sync object in releaseBuffer. (This is deprecated in favor of - // mFence, below.) - //EGLSyncKHR mEglFence; - - // mFence is a fence which will signal when work initiated by the - // previous owner of the buffer is finished. When the buffer is FREE, - // the fence indicates when the consumer has finished reading - // from the buffer, or when the producer has finished writing if it - // called cancelBuffer after queueing some writes. When the buffer is - // QUEUED, it indicates when the producer has finished filling the - // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been - // passed to the consumer or producer along with ownership of the - // buffer, and mFence is set to NO_FENCE. - sp<Fence> mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by the - // consumer. This is set when a buffer in ACQUIRED state is freed. - // It causes releaseBuffer to return STALE_BUFFER_SLOT. - bool mNeedsCleanupOnRelease; - }; - - // mSlots is the array of buffer slots that must be mirrored on the - // producer side. This allows buffer ownership to be transferred between - // the producer and consumer without sending a GraphicBuffer over binder. - // The entire array is initialized to NULL at construction time, and - // buffers are allocated for a slot when requestBuffer is called with - // that slot's index. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultHeight; - - // mMaxAcquiredBufferCount is the number of buffers that the consumer may - // acquire at one time. It defaults to 1 and can be changed by the - // consumer via the setMaxAcquiredBufferCount method, but this may only be - // done when no producer is connected to the GonkBufferQueue. - // - // This value is used to derive the value returned for the - // MIN_UNDEQUEUED_BUFFERS query by the producer. - int mMaxAcquiredBufferCount; - - // mDefaultMaxBufferCount is the default limit on the number of buffers - // that will be allocated at one time. This default limit is set by the - // consumer. The limit (as opposed to the default limit) may be - // overridden by the producer. - int mDefaultMaxBufferCount; - - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the image producer by - // calling setBufferCount. The default is zero, which means the producer - // doesn't care about the number of buffers in the pool. In that case - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - - // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to - // allocate new GraphicBuffer objects. - sp<IGraphicBufferAlloc> mGraphicBufferAlloc; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially set - // to NULL and is written by consumerConnect and consumerDisconnect. - sp<ConsumerListener> mConsumerListener; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - // mAllowSynchronousMode whether we allow synchronous mode or not. Set - // when the GonkBufferQueue is created (by the consumer). - const bool mAllowSynchronousMode; - - // mConnectedApi indicates the producer API that is currently connected - // to this GonkBufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets - // updated by the connect and disconnect methods. - int mConnectedApi; - - // mDequeueCondition condition used for dequeueBuffer in synchronous mode - mutable Condition mDequeueCondition; - - // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector<int> Fifo; - Fifo mQueue; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume image buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A GonkBufferQueue that has been abandoned will - // return the NO_INIT error from all IGraphicBufferProducer methods - // capable of returning an error. - bool mAbandoned; - - // mConsumerName is a string used to identify the GonkBufferQueue in log - // messages. It is set by the setConsumerName method. - String8 mConsumerName; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkBufferQueue objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call. - uint64_t mFrameCounter; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is - // reset when something causes all buffers to be freed (e.g. changing the - // buffer count). - bool mBufferHasBeenQueued; - - // mDefaultBufferFormat can be set so it will override - // the buffer format when it isn't specified in dequeueBuffer - uint32_t mDefaultBufferFormat; - - // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers - uint32_t mConsumerUsageBits; - - // mTransformHint is used to optimize for screen rotations - uint32_t mTransformHint; - -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp deleted file mode 100644 index 0c5cdfeb9..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include <utils/Log.h> -#include <utils/Trace.h> -#include <utils/CallStack.h> -#include <cutils/compiler.h> - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "GonkBufferQueueKK.h" - -#define ATRACE_BUFFER_INDEX(index) - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -static const char* scalingModeName(int scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode, - const sp<IGraphicBufferAlloc>& allocator) : - mDefaultWidth(1), - mDefaultHeight(1), - mMaxAcquiredBufferCount(1), - mDefaultMaxBufferCount(2), - mOverrideMaxBufferCount(0), - mSynchronousMode(true), - mConsumerControlledByApp(false), - mDequeueBufferCannotBlock(false), - mUseAsyncBuffer(true), - mConnectedApi(NO_CONNECTED_API), - mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mConsumerUsageBits(0), - mTransformHint(0) -{ - // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - ALOGV("GonkBufferQueue"); -} - -GonkBufferQueue::~GonkBufferQueue() { - ALOGV("~GonkBufferQueue"); -} - -status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) { - if (count < 2 || count > NUM_BUFFER_SLOTS) - return BAD_VALUE; - - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -void GonkBufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock lock(mMutex); - mDefaultBufferFormat = defaultFormat; - return NO_ERROR; -} - -status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) { - Mutex::Autolock lock(mMutex); - mConsumerUsageBits = usage; - return NO_ERROR; -} - -status_t GonkBufferQueue::setTransformHint(uint32_t hint) { - ALOGV("setTransformHint: %02x", hint); - Mutex::Autolock lock(mMutex); - mTransformHint = hint; - return NO_ERROR; -} - -already_AddRefed<TextureClient> -GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) -{ - Mutex::Autolock _l(mMutex); - if (buffer == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return nullptr; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { - RefPtr<TextureClient> client(mSlots[i].mTextureClient); - return client.forget(); - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return nullptr; -} - -int GonkBufferQueue::getSlotFromTextureClientLocked( - TextureClient* client) const -{ - if (client == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return BAD_VALUE; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mTextureClient == client) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); - return BAD_VALUE; -} - -status_t GonkBufferQueue::setBufferCount(int bufferCount) { - ALOGV("setBufferCount: count=%d", bufferCount); - - sp<IConsumerListener> listener; - { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("setBufferCount: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (bufferCount > NUM_BUFFER_SLOTS) { - ALOGE("setBufferCount: bufferCount too large (max %d)", - NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - // Error out if the user has dequeued buffers - for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { - ALOGE("setBufferCount: client owns some buffers"); - return -EINVAL; - } - } - - if (bufferCount == 0) { - mOverrideMaxBufferCount = 0; - mDequeueCondition.broadcast(); - return NO_ERROR; - } - - // fine to assume async to false before we're setting the buffer count - const int minBufferSlots = getMinMaxBufferCountLocked(false); - if (bufferCount < minBufferSlots) { - ALOGE("setBufferCount: requested buffer count (%d) is less than " - "minimum (%d)", bufferCount, minBufferSlots); - return BAD_VALUE; - } - - // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. We don't clear the - // queue, however, so currently queued buffers still get displayed. - // XXX: Should this use drainQueueAndFreeBuffersLocked instead? - freeAllBuffersLocked(); - mOverrideMaxBufferCount = bufferCount; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } // scope for lock - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return NO_ERROR; -} - -int GonkBufferQueue::query(int what, int* outValue) -{ - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("query: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mDefaultBufferFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = getMinUndequeuedBufferCount(false); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mQueue.size() >= 2); - break; - case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - value = mConsumerUsageBits; - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - -status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) { - ATRACE_CALL(); - ALOGV("requestBuffer: slot=%d", slot); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ALOGE("requestBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (slot < 0 || slot >= NUM_BUFFER_SLOTS) { - ALOGE("requestBuffer: slot index out of range [0, %d]: %d", - NUM_BUFFER_SLOTS, slot); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("requestBuffer: slot %d is not owned by the client (state=%d)", - slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - ATRACE_CALL(); - ALOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); - - if ((w && !h) || (!w && h)) { - ALOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); - return BAD_VALUE; - } - - status_t returnFlags(OK); - int buf = INVALID_BUFFER_SLOT; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (format == 0) { - format = mDefaultBufferFormat; - } - // turn on usage bits the consumer requested - usage |= mConsumerUsageBits; - - int found = -1; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ALOGE("dequeueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - const int maxBufferCount = getMaxBufferCountLocked(async); - if (async && mOverrideMaxBufferCount) { - // FIXME: some drivers are manually setting the buffer-count (which they - // shouldn't), so we do this extra test here to handle that case. - // This is TEMPORARY, until we get this fixed. - if (mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("dequeueBuffer: async mode is invalid with buffercount override"); - return BAD_VALUE; - } - } - - // Free up any buffers that are in slots beyond the max buffer - // count. - //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - // assert(mSlots[i].mBufferState == BufferSlot::FREE); - // if (mSlots[i].mGraphicBuffer != NULL) { - // freeBufferLocked(i); - // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; - // } - //} - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - int dequeuedCount = 0; - int acquiredCount = 0; - for (int i = 0; i < maxBufferCount; i++) { - const int state = mSlots[i].mBufferState; - switch (state) { - case BufferSlot::DEQUEUED: - dequeuedCount++; - break; - case BufferSlot::ACQUIRED: - acquiredCount++; - break; - case BufferSlot::FREE: - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - if ((found < 0) || - mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { - found = i; - } - break; - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mOverrideMaxBufferCount && dequeuedCount) { - ALOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below. - if (mBufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = getMinUndequeuedBufferCount(async); - if (newUndequeuedCount < minUndequeuedCount) { - ALOGE("dequeueBuffer: min undequeued buffer count (%d) " - "exceeded (dequeued=%d undequeudCount=%d)", - minUndequeuedCount, dequeuedCount, - newUndequeuedCount); - return -EBUSY; - } - } - - // If no buffer is found, wait for a buffer to be released or for - // the max buffer count to change. - tryAgain = found == INVALID_BUFFER_SLOT; - if (tryAgain) { - // return an error if we're in "cannot block" mode (producer and consumer - // are controlled by the application) -- however, the consumer is allowed - // to acquire briefly an extra buffer (which could cause us to have to wait here) - // and that's okay because we know the wait will be brief (it happens - // if we dequeue a buffer while the consumer has acquired one but not released - // the old one yet -- for e.g.: see GLConsumer::updateTexImage()). - if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) { - ALOGE("dequeueBuffer: would block! returning an error instead."); - return WOULD_BLOCK; - } - mDequeueCondition.wait(mMutex); - } - } - - - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ALOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - buf = found; - *outBuf = found; - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - mSlots[buf].mAcquireCalled = false; - mSlots[buf].mGraphicBuffer = NULL; - mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = Fence::NO_FENCE; - if (mSlots[buf].mTextureClient) { - mSlots[buf].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr<TextureClientReleaseTask> task = - MakeAndAddRef<TextureClientReleaseTask>(mSlots[buf].mTextureClient); - mSlots[buf].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; - } - - - if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) { - ALOGE("dequeueBuffer: about to return a NULL fence from mSlot. " - "buf=%d, w=%d, h=%d, format=%d", - buf, buffer->width, buffer->height, buffer->format); - } - *outFence = mSlots[buf].mFence; - mSlots[buf].mFence = Fence::NO_FENCE; - } // end lock scope - - if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - - RefPtr<LayersIPCChannel> allocator = ImageBridgeChild::GetSingleton(); - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - GrallocTextureData* texData = GrallocTextureData::Create(IntSize(w, h), format, - gfx::BackendType::NONE, usage, - allocator); - if (!texData) { - return -ENOMEM; - } - - RefPtr<TextureClient> textureClient = new TextureClient(texData, TextureFlags::RECYCLE | TextureFlags::DEALLOCATE_CLIENT, allocator); - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - mSlots[buf].mGraphicBuffer = texData->GetGraphicBuffer(); - mSlots[buf].mTextureClient = textureClient; - ALOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, - mSlots[buf].mGraphicBuffer->handle); - - } - - } - - ALOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf, - mSlots[*outBuf].mFrameNumber, - mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t GonkBufferQueue::setSynchronousMode(bool enabled) { - ALOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mSynchronousMode != enabled) { - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return OK; -} - -status_t GonkBufferQueue::queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output) { - ATRACE_CALL(); - - Rect crop; - uint32_t transform; - int scalingMode; - int64_t timestamp; - bool isAutoTimestamp; - bool async; - sp<Fence> fence; - - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence); - - if (fence == NULL) { - ALOGE("queueBuffer: fence is NULL"); - return BAD_VALUE; - } - - ALOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " - "scale=%s", - buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: - break; - default: - ALOGE("unknown scaling mode: %d", scalingMode); - return -EINVAL; - } - - sp<IConsumerListener> listener; - - { // scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("queueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - const int maxBufferCount = getMaxBufferCountLocked(async); - if (async && mOverrideMaxBufferCount) { - // FIXME: some drivers are manually setting the buffer-count (which they - // shouldn't), so we do this extra test here to handle that case. - // This is TEMPORARY, until we get this fixed. - if (mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("queueBuffer: async mode is invalid with buffercount override"); - return BAD_VALUE; - } - } - if (buf < 0 || buf >= maxBufferCount) { - ALOGE("queueBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); - return -EINVAL; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("queueBuffer: slot %d is not owned by the client " - "(state=%d)", buf, mSlots[buf].mBufferState); - return -EINVAL; - } else if (!mSlots[buf].mRequestBufferCalled) { - ALOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", buf); - return -EINVAL; - } - - ALOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] " - "tr=%#x scale=%s", - buf, mFrameCounter + 1, timestamp, - crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedCrop; - crop.intersect(bufferRect, &croppedCrop); - if (croppedCrop != crop) { - ALOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", buf); - return -EINVAL; - } - - mSlots[buf].mFence = fence; - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - - BufferItem item; - item.mAcquireCalled = mSlots[buf].mAcquireCalled; - item.mGraphicBuffer = mSlots[buf].mGraphicBuffer; - item.mCrop = crop; - item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; - item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); - item.mScalingMode = scalingMode; - item.mTimestamp = timestamp; - item.mIsAutoTimestamp = isAutoTimestamp; - item.mFrameNumber = mFrameCounter; - item.mBuf = buf; - item.mFence = fence; - item.mIsDroppable = mDequeueBufferCannotBlock || async; - - if (mQueue.empty()) { - // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and - // simply queue this buffer. - mQueue.push_back(item); - } else { - // when the queue is not empty, we need to look at the front buffer - // state and see if we need to replace it. - Fifo::iterator front(mQueue.begin()); - if (front->mIsDroppable || !mSynchronousMode) { - // buffer slot currently queued is marked free if still tracked - if (stillTracking(front)) { - mSlots[front->mBuf].mBufferState = BufferSlot::FREE; - // reset the frame number of the freed buffer so that it is the first in - // line to be dequeued again. - mSlots[front->mBuf].mFrameNumber = 0; - } - // and we record the new buffer in the queued list - *front = item; - } else { - mQueue.push_back(item); - } - } - // always signals that an additional frame should be consumed - // to handle max acquired buffer count reached case. - listener = mConsumerListener; - - mBufferHasBeenQueued = true; - mDequeueCondition.broadcast(); - - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - - } // scope for the lock - - // call back without lock held - if (listener != 0) { - listener->onFrameAvailable(); - } - return NO_ERROR; -} - -void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) { - ATRACE_CALL(); - ALOGV("cancelBuffer: slot=%d", buf); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGW("cancelBuffer: GonkBufferQueue has been abandoned!"); - return; - } - - if (buf < 0 || buf >= NUM_BUFFER_SLOTS) { - ALOGE("cancelBuffer: slot index out of range [0, %d]: %d", - NUM_BUFFER_SLOTS, buf); - return; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - buf, mSlots[buf].mBufferState); - return; - } else if (fence == NULL) { - ALOGE("cancelBuffer: fence is NULL"); - return; - } - mSlots[buf].mBufferState = BufferSlot::FREE; - mSlots[buf].mFrameNumber = 0; - mSlots[buf].mFence = fence; - mDequeueCondition.broadcast(); -} - - -status_t GonkBufferQueue::connect(const sp<IBinder>& token, - int api, bool producerControlledByApp, QueueBufferOutput* output) { - ATRACE_CALL(); - ALOGV("connect: api=%d producerControlledByApp=%s", api, - producerControlledByApp ? "true" : "false"); - Mutex::Autolock lock(mMutex); - -retry: - if (mAbandoned) { - ALOGE("connect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mConsumerListener == NULL) { - ALOGE("connect: GonkBufferQueue has no consumer!"); - return NO_INIT; - } - - if (mConnectedApi != NO_CONNECTED_API) { - ALOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - return -EINVAL; - } - - // If we disconnect and reconnect quickly, we can be in a state where our slots are - // empty but we have many buffers in the queue. This can cause us to run out of - // memory if we outrun the consumer. Wait here if it looks like we have too many - // buffers queued up. - int maxBufferCount = getMaxBufferCountLocked(false); // worst-case, i.e. largest value - if (mQueue.size() > (size_t) maxBufferCount) { - // TODO: make this bound tighter? - ALOGV("queue size is %d, waiting", mQueue.size()); - mDequeueCondition.wait(mMutex); - goto retry; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); - - // set-up a death notification so that we can disconnect - // automatically when/if the remote producer dies. - if (token != NULL && token->remoteBinder() != NULL) { - status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this)); - if (err == NO_ERROR) { - mConnectedProducerToken = token; - } else { - ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); - } - } - break; - default: - err = -EINVAL; - break; - } - - mBufferHasBeenQueued = false; - mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; - - return err; -} - -void GonkBufferQueue::binderDied(const wp<IBinder>& who) { - // If we're here, it means that a producer we were connected to died. - // We're GUARANTEED that we still are connected to it because it has no other way - // to get disconnected -- or -- we wouldn't be here because we're removing this - // callback upon disconnect. Therefore, it's okay to read mConnectedApi without - // synchronization here. - int api = mConnectedApi; - this->disconnect(api); -} - -status_t GonkBufferQueue::disconnect(int api) { - ATRACE_CALL(); - ALOGV("disconnect: api=%d", api); - - int err = NO_ERROR; - sp<IConsumerListener> listener; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // it is not really an error to disconnect after the surface - // has been abandoned, it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - freeAllBuffersLocked(); - mConnectedApi = NO_CONNECTED_API; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } else { - ALOGE("disconnect: connected to another api (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } - break; - default: - ALOGE("disconnect: unknown API %d", api); - err = -EINVAL; - break; - } - } - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return err; -} - -void GonkBufferQueue::dumpToString(String8& result, const char* prefix) const { - Mutex::Autolock _l(mMutex); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#llx, scale=%s\n", - i->mBuf, i->mGraphicBuffer.get(), - i->mCrop.left, i->mCrop.top, i->mCrop.right, - i->mCrop.bottom, i->mTransform, i->mTimestamp, - scalingModeName(i->mScalingMode) - ); - i++; - fifoSize++; - } - - - result.appendFormat( - "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, - mDefaultHeight, mDefaultBufferFormat, mTransformHint, - fifoSize, fifo.string()); - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - // just trim the free buffers to not spam the dump - int maxBufferCount = 0; - for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) { - const BufferSlot& slot(mSlots[i]); - if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) { - maxBufferCount = i+1; - break; - } - } - - for (int i=0 ; i<maxBufferCount ; i++) { - const BufferSlot& slot(mSlots[i]); - const sp<GraphicBuffer>& buf(slot.mGraphicBuffer); - result.appendFormat( - "%s%s[%02d:%p] state=%-8s", - prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(), - stateName(slot.mBufferState) - ); - - if (buf != NULL) { - result.appendFormat( - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - } - result.append("\n"); - } -} - -void GonkBufferQueue::freeAllBuffersLocked() -{ - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].mGraphicBuffer = 0; - if (mSlots[i].mTextureClient) { - mSlots[i].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr<TextureClientReleaseTask> task = - MakeAndAddRef<TextureClientReleaseTask>(mSlots[i].mTextureClient); - mSlots[i].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - mSlots[i].mNeedsCleanupOnRelease = true; - } - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - // destroy fence as GonkBufferQueue now takes ownership - mSlots[i].mFence = Fence::NO_FENCE; - } -} - -status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) { - ATRACE_CALL(); - Mutex::Autolock _l(mMutex); - - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer, so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - numAcquiredBuffers++; - } - } - if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) { - ALOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)", - numAcquiredBuffers, mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (mQueue.empty()) { - return NO_BUFFER_AVAILABLE; - } - - Fifo::iterator front(mQueue.begin()); - - // If expectedPresent is specified, we may not want to return a buffer yet. - // If it's specified and there's more than one buffer queued, we may - // want to drop a buffer. - if (expectedPresent != 0) { - const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second - - // The "expectedPresent" argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired-present time - // is earlier (less) than expectedPresent, meaning it'll be displayed - // on time or possibly late if we show it ASAP, we acquire and return - // it. If we don't want to display it until after the expectedPresent - // time, we return PRESENT_LATER without acquiring it. - // - // To be safe, we don't defer acquisition if expectedPresent is - // more than one second in the future beyond the desired present time - // (i.e. we'd be holding the buffer for a long time). - // - // NOTE: code assumes monotonic time values from the system clock are - // positive. - - // Start by checking to see if we can drop frames. We skip this check - // if the timestamps are being auto-generated by Surface -- if the - // app isn't generating timestamps explicitly, they probably don't - // want frames to be discarded based on them. - while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) { - // If entry[1] is timely, drop entry[0] (and repeat). We apply - // an additional criteria here: we only drop the earlier buffer if - // our desiredPresent falls within +/- 1 second of the expected - // present. Otherwise, bogus desiredPresent times (e.g. 0 or - // a small relative timestamp), which normally mean "ignore the - // timestamp and acquire immediately", would cause us to drop - // frames. - // - // We may want to add an additional criteria: don't drop the - // earlier buffer if entry[1]'s fence hasn't signaled yet. - // - // (Vector front is [0], back is [size()-1]) - const BufferItem& bi(mQueue[1]); - nsecs_t desiredPresent = bi.mTimestamp; - if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || - desiredPresent > expectedPresent) { - // This buffer is set to display in the near future, or - // desiredPresent is garbage. Either way we don't want to - // drop the previous buffer just to get this on screen sooner. - ALOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld", - desiredPresent, expectedPresent, desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - break; - } - ALOGV("pts drop: queue1des=%lld expect=%lld size=%d", - desiredPresent, expectedPresent, mQueue.size()); - if (stillTracking(front)) { - // front buffer is still in mSlots, so mark the slot as free - mSlots[front->mBuf].mBufferState = BufferSlot::FREE; - } - mQueue.erase(front); - front = mQueue.begin(); - } - - // See if the front buffer is due. - nsecs_t desiredPresent = front->mTimestamp; - if (desiredPresent > expectedPresent && - desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - ALOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld", - desiredPresent, expectedPresent, desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; - } - - ALOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld", - desiredPresent, expectedPresent, desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - } - - int buf = front->mBuf; - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mBuf = buf; - buffer->mFence = mSlots[buf].mFence; - ATRACE_BUFFER_INDEX(buf); - - ALOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", - front->mBuf, front->mFrameNumber, - front->mGraphicBuffer->handle); - // if front buffer still being tracked update slot state - if (stillTracking(front)) { - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; - } - - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this - // buffer on the consumer side. - //if (buffer->mAcquireCalled) { - // buffer->mGraphicBuffer = NULL; - //} - - mQueue.erase(front); - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueue::releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& fence) { - ATRACE_CALL(); - - if (buf == INVALID_BUFFER_SLOT || fence == NULL) { - return BAD_VALUE; - } - - Mutex::Autolock _l(mMutex); - - // If the frame number has changed because buffer has been reallocated, - // we can ignore this releaseBuffer for the old buffer. - //if (frameNumber != mSlots[buf].mFrameNumber) { - // return STALE_BUFFER_SLOT; - //} - - - // Internal state consistency checks: - // Make sure this buffers hasn't been queued while we were owning it (acquired) - Fifo::iterator front(mQueue.begin()); - Fifo::const_iterator const end(mQueue.end()); - while (front != end) { - if (front->mBuf == buf) { - LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been " - "acquired", mConsumerName.string(), frameNumber, buf); - break; // never reached - } - front++; - } - - // The buffer can now only be released if its in the acquired state - if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mFence = fence; - mSlots[buf].mBufferState = BufferSlot::FREE; - } else if (mSlots[buf].mNeedsCleanupOnRelease) { - ALOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); - mSlots[buf].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ALOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); - return -EINVAL; - } - - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener, - bool controlledByApp) { - ALOGV("consumerConnect controlledByApp=%s", - controlledByApp ? "true" : "false"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("consumerConnect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (consumerListener == NULL) { - ALOGE("consumerConnect: consumerListener may not be NULL"); - return BAD_VALUE; - } - - mConsumerListener = consumerListener; - mConsumerControlledByApp = controlledByApp; - - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerDisconnect() { - ALOGV("consumerDisconnect"); - Mutex::Autolock lock(mMutex); - - if (mConsumerListener == NULL) { - ALOGE("consumerDisconnect: No consumer is connected!"); - return -EINVAL; - } - - mAbandoned = true; - mConsumerListener = NULL; - mQueue.clear(); - freeAllBuffersLocked(); - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) { - ALOGV("getReleasedBuffers"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - uint32_t mask = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (!mSlots[i].mAcquireCalled) { - mask |= 1 << i; - } - } - - // Remove buffers in flight (on the queue) from the mask where acquire has - // been called, as the consumer will not receive the buffer address, so - // it should not free these slots. - Fifo::iterator front(mQueue.begin()); - while (front != mQueue.end()) { - if (front->mAcquireCalled) - mask &= ~(1 << front->mBuf); - front++; - } - - *slotMask = mask; - - ALOGV("getReleasedBuffers: returning mask %#x", mask); - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) { - ALOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ALOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - return setDefaultMaxBufferCountLocked(bufferCount); -} - -status_t GonkBufferQueue::disableAsyncBuffer() { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - if (mConsumerListener != NULL) { - ALOGE("disableAsyncBuffer: consumer already connected!"); - return INVALID_OPERATION; - } - mUseAsyncBuffer = false; - return NO_ERROR; -} - -status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) { - ALOGE("setMaxAcquiredBufferCount: invalid count specified: %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - if (mConnectedApi != NO_CONNECTED_API) { - return INVALID_OPERATION; - } - mMaxAcquiredBufferCount = maxAcquiredBuffers; - return NO_ERROR; -} - -int GonkBufferQueue::getMinUndequeuedBufferCount(bool async) const { - // if dequeueBuffer is allowed to error out, we don't have to - // add an extra buffer. - if (!mUseAsyncBuffer) - return mMaxAcquiredBufferCount; - - // we're in async mode, or we want to prevent the app to - // deadlock itself, we throw-in an extra buffer to guarantee it. - if (mDequeueBufferCannotBlock || async || !mSynchronousMode) - return mMaxAcquiredBufferCount + 1; - - return mMaxAcquiredBufferCount; -} - -int GonkBufferQueue::getMinMaxBufferCountLocked(bool async) const { - return getMinUndequeuedBufferCount(async) + 1; -} - -int GonkBufferQueue::getMaxBufferCountLocked(bool async) const { - int minMaxBufferCount = getMinMaxBufferCountLocked(async); - - int maxBufferCount = mDefaultMaxBufferCount; - if (maxBufferCount < minMaxBufferCount) { - maxBufferCount = minMaxBufferCount; - } - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } - - // Any buffers that are dequeued by the producer or sitting in the queue - // waiting to be consumed need to have their slots preserved. Such - // buffers will temporarily keep the max buffer count up until the slots - // no longer need to be preserved. - for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - BufferSlot::BufferState state = mSlots[i].mBufferState; - if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { - maxBufferCount = i + 1; - } - } - - return maxBufferCount; -} - -bool GonkBufferQueue::stillTracking(const BufferItem *item) const { - const BufferSlot &slot = mSlots[item->mBuf]; - - ALOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, " - "slot: { slot=%d/%llu, buffer=%p }", - item->mBuf, item->mFrameNumber, - (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), - item->mBuf, slot.mFrameNumber, - (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); - - // Compare item with its original buffer slot. We can check the slot - // as the buffer would not be moved to a different slot by the producer. - return (slot.mGraphicBuffer != NULL && - item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); -} - -GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp<ConsumerListener>& consumerListener): - mConsumerListener(consumerListener) {} - -GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueKK.h b/widget/gonk/nativewindow/GonkBufferQueueKK.h deleted file mode 100644 index 01905427d..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueKK.h +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_KK_H -#define NATIVEWINDOW_GONKBUFFERQUEUE_KK_H - -#include <gui/IConsumerListener.h> -#include <gui/IGraphicBufferAlloc.h> -#include <gui/IGraphicBufferProducer.h> -#include "IGonkGraphicBufferConsumer.h" - -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> - -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -#include "mozilla/layers/LayersSurfaces.h" -#include "mozilla/layers/TextureClient.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class GonkBufferQueue : public BnGraphicBufferProducer, - public BnGonkGraphicBufferConsumer, - private IBinder::DeathRecipient -{ - typedef mozilla::layers::TextureClient TextureClient; - -public: - enum { MIN_UNDEQUEUED_BUFFERS = 2 }; - enum { NUM_BUFFER_SLOTS = 32 }; - enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; - enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER }; - - // When in async mode we reserve two slots in order to guarantee that the - // producer and consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - - // for backward source compatibility - typedef ::android::ConsumerListener ConsumerListener; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // GonkBufferQueue object and the consumer object. The reason this can't be a weak - // reference in the GonkBufferQueue class is because we're planning to expose the - // consumer side of a GonkBufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public BnConsumerListener { - public: - ProxyConsumerListener(const wp<ConsumerListener>& consumerListener); - virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - private: - // mConsumerListener is a weak reference to the IConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp<ConsumerListener> mConsumerListener; - }; - - - // BufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allocator is used to allocate all the - // needed gralloc buffers. - GonkBufferQueue(bool allowSynchronousMode = true, - const sp<IGraphicBufferAlloc>& allocator = NULL); - virtual ~GonkBufferQueue(); - - /* - * IBinder::DeathRecipient interface - */ - - virtual void binderDied(const wp<IBinder>& who); - - /* - * IGraphicBufferProducer interface - */ - - // Query native window attributes. The "what" values are enumerated in - // window.h (e.g. NATIVE_WINDOW_FORMAT). - virtual int query(int what, int* value); - - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the GonkBufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); - - // requestBuffer returns the GraphicBuffer for slot N. - // - // In normal operation, this is called the first time slot N is returned - // by dequeueBuffer. It must be called again if dequeueBuffer returns - // flags indicating that previously-returned buffers are no longer valid. - virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - - // dequeueBuffer gets the next buffer slot index for the producer to use. - // If a buffer slot is available then that slot index is written to the - // location pointed to by the buf argument and a status of OK is returned. - // If no slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // - // The fence parameter will be updated to hold the fence associated with - // the buffer. The contents of the buffer must not be overwritten until the - // fence signals. If the fence is Fence::NO_FENCE, the buffer may be - // written immediately. - // - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. If width and height are both zero, the - // default values specified by setDefaultBufferSize() are used instead. - // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. - // - // The usage argument specifies gralloc buffer usage flags. The values - // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These - // will be merged with the usage flags specified by setConsumerUsageBits. - // - // The return value may be a negative error value or a non-negative - // collection of flags. If the flags are set, the return values are - // valid, but additional actions must be performed. - // - // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the - // producer must discard cached GraphicBuffer references for the slot - // returned in buf. - // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer - // must discard cached GraphicBuffer references for all slots. - // - // In both cases, the producer will need to call requestBuffer to get a - // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); - - // queueBuffer returns a filled buffer to the GonkBufferQueue. - // - // Additional data is provided in the QueueBufferInput struct. Notably, - // a timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are producer-specific and should be documented by the - // producer. - // - // The caller may provide a fence that signals when all rendering - // operations have completed. Alternatively, NO_FENCE may be used, - // indicating that the buffer is ready immediately. - // - // Some values are returned in the output struct: the current settings - // for default width and height, the current transform hint, and the - // number of queued buffers. - virtual status_t queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output); - - // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't - // queue it for use by the consumer. - // - // The buffer will not be overwritten until the fence signals. The fence - // will usually be the one obtained from dequeueBuffer. - virtual void cancelBuffer(int buf, const sp<Fence>& fence); - - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is synchronous. - // This should be called only during initialization. - virtual status_t setSynchronousMode(bool enabled); - - // connect attempts to connect a producer API to the GonkBufferQueue. This - // must be called before any other IGraphicBufferProducer methods are - // called except for getAllocator. A consumer must already be connected. - // - // This method will fail if connect was previously called on the - // GonkBufferQueue and no corresponding disconnect call was made (i.e. if - // it's still connected to a producer). - // - // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(const sp<IBinder>& token, - int api, bool producerControlledByApp, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer API from the GonkBufferQueue. - // Calling this method will cause any subsequent calls to other - // IGraphicBufferProducer methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the GonkBufferQueue is not currently - // connected to the specified producer API. - virtual status_t disconnect(int api); - - /* - * IGraphicBufferConsumer interface - */ - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the GonkBufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - // - // If presentWhen is nonzero, it indicates the time when the buffer will - // be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen); - - // releaseBuffer releases a buffer slot from the consumer back to the - // GonkBufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - const sp<Fence>& releaseFence); - - // consumerConnect connects a consumer to the GonkBufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // GonkBufferQueue is placed into the "abandoned" state, causing most - // interactions with the GonkBufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumer may not be NULL. - virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp); - - // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All - // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" - // state, causing most interactions with the GonkBufferQueue by the producer to - // fail. - virtual status_t consumerDisconnect(); - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots have been released by the GonkBufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - virtual status_t getReleasedBuffers(uint32_t* slotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount); - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - virtual status_t disableAsyncBuffer(); - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the GonkBufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - virtual status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - virtual status_t setTransformHint(uint32_t hint); - - // dump our state in a String - virtual void dumpToString(String8& result, const char* prefix) const; - - already_AddRefed<TextureClient> getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - int getSlotFromTextureClientLocked(TextureClient* client) const; - -private: - // freeBufferLocked frees the GraphicBuffer and sync resources for the - // given slot. - //void freeBufferLocked(int index); - - // freeAllBuffersLocked frees the GraphicBuffer and sync resources for - // all slots. - void freeAllBuffersLocked(); - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - // The initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); - - // getMinUndequeuedBufferCount returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. - // The async parameter tells whether we're in asynchronous mode. - int getMinUndequeuedBufferCount(bool async) const; - - // getMinBufferCountLocked returns the minimum number of buffers allowed - // given the current GonkBufferQueue state. - // The async parameter tells whether we're in asynchronous mode. - int getMinMaxBufferCountLocked(bool async) const; - - // getMaxBufferCountLocked returns the maximum number of buffers that can - // be allocated at once. This value depends upon the following member - // variables: - // - // mDequeueBufferCannotBlock - // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // async parameter - // - // Any time one of these member variables is changed while a producer is - // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked(bool async) const; - - // stillTracking returns true iff the buffer item is still being tracked - // in one of the slots. - bool stillTracking(const BufferItem *item) const; - - struct BufferSlot { - - BufferSlot() - : mBufferState(BufferSlot::FREE), - mRequestBufferCalled(false), - mFrameNumber(0), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false) { - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp<GraphicBuffer> mGraphicBuffer; - - // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. - RefPtr<TextureClient> mTextureClient; - - // BufferState represents the different states in which a buffer slot - // can be. All slots are initially FREE. - enum BufferState { - // FREE indicates that the buffer is available to be dequeued - // by the producer. The buffer may be in use by the consumer for - // a finite time, so the buffer must not be modified until the - // associated fence is signaled. - // - // The slot is "owned" by GonkBufferQueue. It transitions to DEQUEUED - // when dequeueBuffer is called. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // producer, but has not yet been queued or canceled. The - // producer may modify the buffer's contents as soon as the - // associated ready fence is signaled. - // - // The slot is "owned" by the producer. It can transition to - // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been filled by the - // producer and queued for use by the consumer. The buffer - // contents may continue to be modified for a finite time, so - // the contents must not be accessed until the associated fence - // is signaled. - // - // The slot is "owned" by GonkBufferQueue. It can transition to - // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is - // queued in asynchronous mode). - QUEUED = 2, - - // ACQUIRED indicates that the buffer has been acquired by the - // consumer. As with QUEUED, the contents must not be accessed - // by the consumer until the fence is signaled. - // - // The slot is "owned" by the consumer. It transitions to FREE - // when releaseBuffer is called. - ACQUIRED = 3 - }; - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the producer did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching producer bugs. - bool mRequestBufferCalled; - - // mFrameNumber is the number of the queued frame for this slot. This - // is used to dequeue buffers in LRU order (useful because buffers - // may be released before their release fence is signaled). - uint64_t mFrameNumber; - - // mFence is a fence which will signal when work initiated by the - // previous owner of the buffer is finished. When the buffer is FREE, - // the fence indicates when the consumer has finished reading - // from the buffer, or when the producer has finished writing if it - // called cancelBuffer after queueing some writes. When the buffer is - // QUEUED, it indicates when the producer has finished filling the - // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been - // passed to the consumer or producer along with ownership of the - // buffer, and mFence is set to NO_FENCE. - sp<Fence> mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by the - // consumer. This is set when a buffer in ACQUIRED state is freed. - // It causes releaseBuffer to return STALE_BUFFER_SLOT. - bool mNeedsCleanupOnRelease; - }; - - // mSlots is the array of buffer slots that must be mirrored on the - // producer side. This allows buffer ownership to be transferred between - // the producer and consumer without sending a GraphicBuffer over binder. - // The entire array is initialized to NULL at construction time, and - // buffers are allocated for a slot when requestBuffer is called with - // that slot's index. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultHeight; - - // mMaxAcquiredBufferCount is the number of buffers that the consumer may - // acquire at one time. It defaults to 1 and can be changed by the - // consumer via the setMaxAcquiredBufferCount method, but this may only be - // done when no producer is connected to the GonkBufferQueue. - // - // This value is used to derive the value returned for the - // MIN_UNDEQUEUED_BUFFERS query by the producer. - int mMaxAcquiredBufferCount; - - // mDefaultMaxBufferCount is the default limit on the number of buffers - // that will be allocated at one time. This default limit is set by the - // consumer. The limit (as opposed to the default limit) may be - // overridden by the producer. - int mDefaultMaxBufferCount; - - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the image producer by - // calling setBufferCount. The default is zero, which means the producer - // doesn't care about the number of buffers in the pool. In that case - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - - // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to - // allocate new GraphicBuffer objects. - sp<IGraphicBufferAlloc> mGraphicBufferAlloc; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially set - // to NULL and is written by consumerConnect and consumerDisconnect. - sp<IConsumerListener> mConsumerListener; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - // mConsumerControlledByApp whether the connected consumer is controlled by the - // application. - bool mConsumerControlledByApp; - - // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block. - // this flag is set during connect() when both consumer and producer are controlled - // by the application. - bool mDequeueBufferCannotBlock; - - // mUseAsyncBuffer whether an extra buffer is used in async mode to prevent - // dequeueBuffer() from ever blocking. - bool mUseAsyncBuffer; - - // mConnectedApi indicates the producer API that is currently connected - // to this GonkBufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets - // updated by the connect and disconnect methods. - int mConnectedApi; - - // mDequeueCondition condition used for dequeueBuffer in synchronous mode - mutable Condition mDequeueCondition; - - // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector<BufferItem> Fifo; - Fifo mQueue; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume image buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A GonkBufferQueue that has been abandoned will - // return the NO_INIT error from all IGraphicBufferProducer methods - // capable of returning an error. - bool mAbandoned; - - // mConsumerName is a string used to identify the GonkBufferQueue in log - // messages. It is set by the setConsumerName method. - String8 mConsumerName; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkBufferQueue objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call, and buffer allocation. - uint64_t mFrameCounter; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is - // reset when something causes all buffers to be freed (e.g. changing the - // buffer count). - bool mBufferHasBeenQueued; - - // mDefaultBufferFormat can be set so it will override - // the buffer format when it isn't specified in dequeueBuffer - uint32_t mDefaultBufferFormat; - - // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers - uint32_t mConsumerUsageBits; - - // mTransformHint is used to optimize for screen rotations - uint32_t mTransformHint; - - // mConnectedProducerToken is used to set a binder death notification on the producer - sp<IBinder> mConnectedProducerToken; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp deleted file mode 100644 index 7df72bf68..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include "GonkBufferItem.h" - -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> - -#include <system/window.h> - -namespace android { - -GonkBufferItem::GonkBufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mSlot(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -GonkBufferItem::operator IGonkGraphicBufferConsumer::BufferItem() const { - IGonkGraphicBufferConsumer::BufferItem bufferItem; - bufferItem.mGraphicBuffer = mGraphicBuffer; - bufferItem.mFence = mFence; - bufferItem.mCrop = mCrop; - bufferItem.mTransform = mTransform; - bufferItem.mScalingMode = mScalingMode; - bufferItem.mTimestamp = mTimestamp; - bufferItem.mIsAutoTimestamp = mIsAutoTimestamp; - bufferItem.mFrameNumber = mFrameNumber; - bufferItem.mBuf = mSlot; - bufferItem.mIsDroppable = mIsDroppable; - bufferItem.mAcquireCalled = mAcquireCalled; - bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse; - return bufferItem; -} - -size_t GonkBufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mSlot) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t GonkBufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t GonkBufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -status_t GonkBufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (count < GonkBufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast<uint32_t*>(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mSlot); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t GonkBufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mSlot); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -const char* GonkBufferItem::scalingModeName(uint32_t scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h deleted file mode 100644 index b2d6d3068..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERITEM_LL_H -#define NATIVEWINDOW_GONKBUFFERITEM_LL_H - -#include "IGonkGraphicBufferConsumerLL.h" - -#include <ui/Rect.h> - -#include <utils/Flattenable.h> -#include <utils/StrongPointer.h> - -namespace android { - -class Fence; -class GraphicBuffer; - -class GonkBufferItem : public Flattenable<GonkBufferItem> { - friend class Flattenable<GonkBufferItem>; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - // The default value of mBuf, used to indicate this doesn't correspond to a slot. - enum { INVALID_BUFFER_SLOT = -1 }; - GonkBufferItem(); - operator IGonkGraphicBufferConsumer::BufferItem() const; - - static const char* scalingModeName(uint32_t scalingMode); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp<Fence> mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h> - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // refer to NATIVE_WINDOW_SCALING_* in <window.h> - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. This value - // is guaranteed to be monotonically increasing for each newly - // acquired buffer. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mSlot; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; -}; - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp deleted file mode 100644 index 1d7eb2702..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include <inttypes.h> - -#define LOG_TAG "GonkBufferQueueConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "GonkBufferItem.h" -#include "GonkBufferQueueConsumer.h" -#include "GonkBufferQueueCore.h" -#include <gui/IConsumerListener.h> -#include <gui/IProducerListener.h> - -namespace android { - -GonkBufferQueueConsumer::GonkBufferQueueConsumer(const sp<GonkBufferQueueCore>& core) : - mCore(core), - mSlots(core->mSlots), - mConsumerName() {} - -GonkBufferQueueConsumer::~GonkBufferQueueConsumer() {} - -status_t GonkBufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::ACQUIRED) { - ++numAcquiredBuffers; - } - } - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - ALOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", - numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - - // Check if the queue is empty. - // In asynchronous mode the list is guaranteed to be one buffer deep, - // while in synchronous mode we use the oldest buffer. - if (mCore->mQueue.empty()) { - return NO_BUFFER_AVAILABLE; - } - - GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - - // If expectedPresent is specified, we may not want to return a buffer yet. - // If it's specified and there's more than one buffer queued, we may want - // to drop a buffer. - if (expectedPresent != 0) { - const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second - - // The 'expectedPresent' argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired present time is - // earlier (less) than expectedPresent -- meaning it will be displayed - // on time or possibly late if we show it as soon as possible -- we - // acquire and return it. If we don't want to display it until after the - // expectedPresent time, we return PRESENT_LATER without acquiring it. - // - // To be safe, we don't defer acquisition if expectedPresent is more - // than one second in the future beyond the desired present time - // (i.e., we'd be holding the buffer for a long time). - // - // NOTE: Code assumes monotonic time values from the system clock - // are positive. - - // Start by checking to see if we can drop frames. We skip this check if - // the timestamps are being auto-generated by Surface. If the app isn't - // generating timestamps explicitly, it probably doesn't want frames to - // be discarded based on them. - while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { - // If entry[1] is timely, drop entry[0] (and repeat). We apply an - // additional criterion here: we only drop the earlier buffer if our - // desiredPresent falls within +/- 1 second of the expected present. - // Otherwise, bogus desiredPresent times (e.g., 0 or a small - // relative timestamp), which normally mean "ignore the timestamp - // and acquire immediately", would cause us to drop frames. - // - // We may want to add an additional criterion: don't drop the - // earlier buffer if entry[1]'s fence hasn't signaled yet. - const BufferItem& bufferItem(mCore->mQueue[1]); - nsecs_t desiredPresent = bufferItem.mTimestamp; - if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || - desiredPresent > expectedPresent) { - // This buffer is set to display in the near future, or - // desiredPresent is garbage. Either way we don't want to drop - // the previous buffer just to get this on the screen sooner. - ALOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" - PRId64 " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - break; - } - - ALOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 - " size=%zu", - desiredPresent, expectedPresent, mCore->mQueue.size()); - if (mCore->stillTracking(front)) { - // Front buffer is still in mSlots, so mark the slot as free - mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE; - } - mCore->mQueue.erase(front); - front = mCore->mQueue.begin(); - } - - // See if the front buffer is due - nsecs_t desiredPresent = front->mTimestamp; - if (desiredPresent > expectedPresent && - desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - ALOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 - " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; - } - - ALOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " - "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - } - - int slot = front->mSlot; - //*outBuffer = *front; - outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer; - outBuffer->mFrameNumber = mSlots[slot].mFrameNumber; - outBuffer->mBuf = slot; - outBuffer->mFence = mSlots[slot].mFence; - - ATRACE_BUFFER_INDEX(slot); - - ALOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", - slot, front->mFrameNumber, front->mGraphicBuffer->handle); - // If the front buffer is still being tracked, update its slot state - if (mCore->stillTracking(front)) { - mSlots[slot].mAcquireCalled = true; - mSlots[slot].mNeedsCleanupOnRelease = false; - mSlots[slot].mBufferState = GonkBufferSlot::ACQUIRED; - mSlots[slot].mFence = Fence::NO_FENCE; - } - - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer - // on the consumer side - //if (outBuffer->mAcquireCalled) { - // outBuffer->mGraphicBuffer = NULL; - //} - - mCore->mQueue.erase(front); - - // We might have freed a slot while dropping old buffers, or the producer - // may be blocked waiting for the number of buffers in the queue to - // decrease. - mCore->mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::detachBuffer(int slot) { - ATRACE_CALL(); - ATRACE_BUFFER_INDEX(slot); - ALOGV("detachBuffer(C): slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("detachBuffer(C): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("detachBuffer(C): slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::ACQUIRED) { - ALOGE("detachBuffer(C): slot %d is not owned by the consumer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - - mCore->freeBufferLocked(slot); - mCore->mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::attachBuffer(int* outSlot, - const sp<android::GraphicBuffer>& buffer) { - ATRACE_CALL(); - - if (outSlot == NULL) { - ALOGE("attachBuffer(P): outSlot must not be NULL"); - return BAD_VALUE; - } else if (buffer == NULL) { - ALOGE("attachBuffer(P): cannot attach NULL buffer"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - - // Make sure we don't have too many acquired buffers and find a free slot - // to put the buffer into (the oldest if there are multiple). - int numAcquiredBuffers = 0; - int found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::ACQUIRED) { - ++numAcquiredBuffers; - } else if (mSlots[s].mBufferState == GonkBufferSlot::FREE) { - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } - } - } - - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - ALOGE("attachBuffer(P): max acquired buffer count reached: %d " - "(max %d)", numAcquiredBuffers, - mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - ALOGE("attachBuffer(P): could not find free buffer slot"); - return NO_MEMORY; - } - - *outSlot = found; - ATRACE_BUFFER_INDEX(*outSlot); - ALOGV("attachBuffer(C): returning slot %d", *outSlot); - - mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState = GonkBufferSlot::ACQUIRED; - mSlots[*outSlot].mAttachedByConsumer = true; - mSlots[*outSlot].mNeedsCleanupOnRelease = false; - mSlots[*outSlot].mFence = Fence::NO_FENCE; - mSlots[*outSlot].mFrameNumber = 0; - - // mAcquireCalled tells GonkBufferQueue that it doesn't need to send a valid - // GraphicBuffer pointer on the next acquireBuffer call, which decreases - // Binder traffic by not un/flattening the GraphicBuffer. However, it - // requires that the consumer maintain a cached copy of the slot <--> buffer - // mappings, which is why the consumer doesn't need the valid pointer on - // acquire. - // - // The StreamSplitter is one of the primary users of the attach/detach - // logic, and while it is running, all buffers it acquires are immediately - // detached, and all buffers it eventually releases are ones that were - // attached (as opposed to having been obtained from acquireBuffer), so it - // doesn't make sense to maintain the slot/buffer mappings, which would - // become invalid for every buffer during detach/attach. By setting this to - // false, the valid GraphicBuffer pointer will always be sent with acquire - // for attached buffers. - mSlots[*outSlot].mAcquireCalled = false; - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, - const sp<Fence>& releaseFence) { - ATRACE_CALL(); - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS || - releaseFence == NULL) { - return BAD_VALUE; - } - - sp<IProducerListener> listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - - // If the frame number has changed because the buffer has been reallocated, - // we can ignore this releaseBuffer for the old buffer - //if (frameNumber != mSlots[slot].mFrameNumber) { - // return STALE_BUFFER_SLOT; - //} - - // Make sure this buffer hasn't been queued while acquired by the consumer - GonkBufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); - while (current != mCore->mQueue.end()) { - if (current->mSlot == slot) { - ALOGE("releaseBuffer: buffer slot %d pending release is " - "currently queued", slot); - return BAD_VALUE; - } - ++current; - } - - if (mSlots[slot].mBufferState == GonkBufferSlot::ACQUIRED) { - mSlots[slot].mFence = releaseFence; - mSlots[slot].mBufferState = GonkBufferSlot::FREE; - listener = mCore->mConnectedProducerListener; - ALOGV("releaseBuffer: releasing slot %d", slot); - } else if (mSlots[slot].mNeedsCleanupOnRelease) { - ALOGV("releaseBuffer: releasing a stale buffer slot %d " - "(state = %d)", slot, mSlots[slot].mBufferState); - mSlots[slot].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ALOGV("releaseBuffer: attempted to release buffer slot %d " - "but its state was %d", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - - mCore->mDequeueCondition.broadcast(); - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { - listener->onBufferReleased(); - } - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::connect( - const sp<IConsumerListener>& consumerListener, bool controlledByApp) { - ATRACE_CALL(); - - if (consumerListener == NULL) { - ALOGE("connect(C): consumerListener may not be NULL"); - return BAD_VALUE; - } - - ALOGV("connect(C): controlledByApp=%s", - controlledByApp ? "true" : "false"); - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("connect(C): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - mCore->mConsumerListener = consumerListener; - mCore->mConsumerControlledByApp = controlledByApp; - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::disconnect() { - ATRACE_CALL(); - - ALOGV("disconnect(C)"); - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mConsumerListener == NULL) { - ALOGE("disconnect(C): no consumer is connected"); - return BAD_VALUE; - } - - mCore->mIsAbandoned = true; - mCore->mConsumerListener = NULL; - mCore->mQueue.clear(); - mCore->freeAllBuffersLocked(); - mCore->mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { - ATRACE_CALL(); - - if (outSlotMask == NULL) { - ALOGE("getReleasedBuffers: outSlotMask may not be NULL"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("getReleasedBuffers: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - uint64_t mask = 0; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (!mSlots[s].mAcquireCalled) { - mask |= (1ULL << s); - } - } - - // Remove from the mask queued buffers for which acquire has been called, - // since the consumer will not receive their buffer addresses and so must - // retain their cached information - GonkBufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); - while (current != mCore->mQueue.end()) { - if (current->mAcquireCalled) { - mask &= ~(1ULL << current->mSlot); - } - ++current; - } - - ALOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); - *outSlotMask = mask; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setDefaultBufferSize(uint32_t width, - uint32_t height) { - ATRACE_CALL(); - - if (width == 0 || height == 0) { - ALOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " - "height=%u)", width, height); - return BAD_VALUE; - } - - ALOGV("setDefaultBufferSize: width=%u height=%u", width, height); - - Mutex::Autolock lock(mCore->mMutex); - mCore->mDefaultWidth = width; - mCore->mDefaultHeight = height; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - return mCore->setDefaultMaxBufferCountLocked(bufferCount); -} - -status_t GonkBufferQueueConsumer::disableAsyncBuffer() { - ATRACE_CALL(); - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mConsumerListener != NULL) { - ALOGE("disableAsyncBuffer: consumer already connected"); - return INVALID_OPERATION; - } - - ALOGV("disableAsyncBuffer"); - mCore->mUseAsyncBuffer = false; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setMaxAcquiredBufferCount( - int maxAcquiredBuffers) { - ATRACE_CALL(); - - if (maxAcquiredBuffers < 1 || - maxAcquiredBuffers > GonkBufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { - ALOGE("setMaxAcquiredBufferCount: invalid count %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mConnectedApi != GonkBufferQueueCore::NO_CONNECTED_API) { - ALOGE("setMaxAcquiredBufferCount: producer is already connected"); - return INVALID_OPERATION; - } - - ALOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); - mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; - return NO_ERROR; -} - -void GonkBufferQueueConsumer::setConsumerName(const String8& name) { - ATRACE_CALL(); - ALOGV("setConsumerName: '%s'", name.string()); - Mutex::Autolock lock(mCore->mMutex); - mCore->mConsumerName = name; - mConsumerName = name; -} - -status_t GonkBufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { - ATRACE_CALL(); - ALOGV("setDefaultBufferFormat: %u", defaultFormat); - Mutex::Autolock lock(mCore->mMutex); - mCore->mDefaultBufferFormat = defaultFormat; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { - ATRACE_CALL(); - ALOGV("setConsumerUsageBits: %#x", usage); - Mutex::Autolock lock(mCore->mMutex); - mCore->mConsumerUsageBits = usage; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setTransformHint(uint32_t hint) { - ATRACE_CALL(); - ALOGV("setTransformHint: %#x", hint); - Mutex::Autolock lock(mCore->mMutex); - mCore->mTransformHint = hint; - return NO_ERROR; -} - -sp<NativeHandle> GonkBufferQueueConsumer::getSidebandStream() const { - return mCore->mSidebandStream; -} - -void GonkBufferQueueConsumer::dumpToString(String8& result, const char* prefix) const { - mCore->dump(result, prefix); -} - -already_AddRefed<GonkBufferSlot::TextureClient> -GonkBufferQueueConsumer::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) -{ - Mutex::Autolock _l(mCore->mMutex); - if (buffer == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return nullptr; - } - - for (int i = 0; i < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { - RefPtr<TextureClient> client(mSlots[i].mTextureClient); - return client.forget(); - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return nullptr; -} - -int -GonkBufferQueueConsumer::getSlotFromTextureClientLocked(GonkBufferSlot::TextureClient* client) const -{ - if (client == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return BAD_VALUE; - } - - for (int i = 0; i < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mTextureClient == client) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); - return BAD_VALUE; -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h deleted file mode 100644 index a97cfab42..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUECONSUMER_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUECONSUMER_LL_H - -#include "GonkBufferQueueDefs.h" -#include "IGonkGraphicBufferConsumerLL.h" - -namespace android { - -class GonkBufferQueueCore; - -class GonkBufferQueueConsumer : public BnGonkGraphicBufferConsumer { - -public: - GonkBufferQueueConsumer(const sp<GonkBufferQueueCore>& core); - virtual ~GonkBufferQueueConsumer(); - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the GonkBufferQueue. If no buffer is pending then it returns - // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the - // information about the buffer is returned in BufferItem. If the buffer - // returned had previously been acquired then the BufferItem::mGraphicBuffer - // field of buffer is set to NULL and it is assumed that the consumer still - // holds a reference to the buffer. - // - // If expectedPresent is nonzero, it indicates the time when the buffer - // will be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - virtual status_t acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent); - - // See IGonkGraphicBufferConsumer::detachBuffer - virtual status_t detachBuffer(int slot); - - // See IGonkGraphicBufferConsumer::attachBuffer - virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // GonkBufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - virtual status_t releaseBuffer(int slot, uint64_t frameNumber, - const sp<Fence>& releaseFence); - - // connect connects a consumer to the GonkBufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // GonkBufferQueue is placed into the "abandoned" state, causing most - // interactions with the GonkBufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumerListener may not be NULL. - virtual status_t connect(const sp<IConsumerListener>& consumerListener, - bool controlledByApp); - - // disconnect disconnects a consumer from the GonkBufferQueue. All - // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" - // state, causing most interactions with the GonkBufferQueue by the producer to - // fail. - virtual status_t disconnect(); - - // getReleasedBuffers sets the value pointed to by outSlotMask to a bit mask - // indicating which buffer slots have been released by the GonkBufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - virtual status_t getReleasedBuffers(uint64_t* outSlotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount); - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before connect(). - virtual status_t disableAsyncBuffer(); - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the GonkBufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - virtual status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - virtual status_t setTransformHint(uint32_t hint); - - // Retrieve the sideband buffer stream, if any. - virtual sp<NativeHandle> getSidebandStream() const; - - // dump our state in a String - virtual void dumpToString(String8& result, const char* prefix) const; - - // Added by mozilla - virtual already_AddRefed<GonkBufferSlot::TextureClient> getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - virtual int getSlotFromTextureClientLocked(GonkBufferSlot::TextureClient* client) const; - - // Functions required for backwards compatibility. - // These will be modified/renamed in IGonkGraphicBufferConsumer and will be - // removed from this class at that time. See b/13306289. - virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, - bool controlledByApp) { - return connect(consumer, controlledByApp); - } - - virtual status_t consumerDisconnect() { return disconnect(); } - - // End functions required for backwards compatibility - -private: - sp<GonkBufferQueueCore> mCore; - - // This references mCore->mSlots. Lock mCore->mMutex while accessing. - GonkBufferQueueDefs::SlotsType& mSlots; - - // This is a cached copy of the name stored in the GonkBufferQueueCore. - // It's updated during setConsumerName. - String8 mConsumerName; - -}; // class GonkBufferQueueConsumer - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp deleted file mode 100644 index 9e8e337f6..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueueCore" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include <inttypes.h> - -#include "GonkBufferItem.h" -#include "GonkBufferQueueCore.h" -#include <gui/IConsumerListener.h> -#include <gui/IGraphicBufferAlloc.h> -#include <gui/IProducerListener.h> -#include <gui/ISurfaceComposer.h> -#include <private/gui/ComposerService.h> - -#include <cutils/compiler.h> -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" - -template <typename T> -static inline T max(T a, T b) { return a > b ? a : b; } - -namespace android { - -static String8 getUniqueName() { - static volatile int32_t counter = 0; - return String8::format("unnamed-%d-%d", getpid(), - android_atomic_inc(&counter)); -} - -GonkBufferQueueCore::GonkBufferQueueCore(const sp<IGraphicBufferAlloc>& allocator) : - mAllocator(allocator), - mMutex(), - mIsAbandoned(false), - mConsumerControlledByApp(false), - mConsumerName(getUniqueName()), - mConsumerListener(), - mConsumerUsageBits(0), - mConnectedApi(NO_CONNECTED_API), - mConnectedProducerListener(), - mSlots(), - mQueue(), - mOverrideMaxBufferCount(0), - mDequeueCondition(), - mUseAsyncBuffer(true), - mDequeueBufferCannotBlock(false), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mDefaultWidth(1), - mDefaultHeight(1), - mDefaultMaxBufferCount(2), - mMaxAcquiredBufferCount(1), - mBufferHasBeenQueued(false), - mFrameCounter(0), - mTransformHint(0), - mIsAllocating(false), - mIsAllocatingCondition() -{ - ALOGV("GonkBufferQueueCore"); -} - -GonkBufferQueueCore::~GonkBufferQueueCore() {} - -void GonkBufferQueueCore::dump(String8& result, const char* prefix) const { - Mutex::Autolock lock(mMutex); - - String8 fifo; - Fifo::const_iterator current(mQueue.begin()); - while (current != mQueue.end()) { - fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n", - current->mSlot, current->mGraphicBuffer.get(), - current->mCrop.left, current->mCrop.top, current->mCrop.right, - current->mCrop.bottom, current->mTransform, current->mTimestamp, - GonkBufferItem::scalingModeName(current->mScalingMode)); - ++current; - } - - result.appendFormat("%s-GonkBufferQueue mMaxAcquiredBufferCount=%d, " - "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n", - prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, - mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, - mQueue.size(), fifo.string()); - - // Trim the free buffers so as to not spam the dump - int maxBufferCount = 0; - for (int s = GonkBufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) { - const GonkBufferSlot& slot(mSlots[s]); - if (slot.mBufferState != GonkBufferSlot::FREE || - slot.mGraphicBuffer != NULL) { - maxBufferCount = s + 1; - break; - } - } - - for (int s = 0; s < maxBufferCount; ++s) { - const GonkBufferSlot& slot(mSlots[s]); - const sp<GraphicBuffer>& buffer(slot.mGraphicBuffer); - result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix, - (slot.mBufferState == GonkBufferSlot::ACQUIRED) ? ">" : " ", - s, buffer.get(), - GonkBufferSlot::bufferStateName(slot.mBufferState)); - - if (buffer != NULL) { - result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle, - buffer->width, buffer->height, buffer->stride, - buffer->format); - } - - result.append("\n"); - } -} - -int GonkBufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { - // If dequeueBuffer is allowed to error out, we don't have to add an - // extra buffer. - if (!mUseAsyncBuffer) { - return mMaxAcquiredBufferCount; - } - - if (mDequeueBufferCannotBlock || async) { - return mMaxAcquiredBufferCount + 1; - } - - return mMaxAcquiredBufferCount; -} - -int GonkBufferQueueCore::getMinMaxBufferCountLocked(bool async) const { - return getMinUndequeuedBufferCountLocked(async) + 1; -} - -int GonkBufferQueueCore::getMaxBufferCountLocked(bool async) const { - int minMaxBufferCount = getMinMaxBufferCountLocked(async); - - int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount); - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } - - // Any buffers that are dequeued by the producer or sitting in the queue - // waiting to be consumed need to have their slots preserved. Such buffers - // will temporarily keep the max buffer count up until the slots no longer - // need to be preserved. - for (int s = maxBufferCount; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - GonkBufferSlot::BufferState state = mSlots[s].mBufferState; - if (state == GonkBufferSlot::QUEUED || state == GonkBufferSlot::DEQUEUED) { - maxBufferCount = s + 1; - } - } - - return maxBufferCount; -} - -status_t GonkBufferQueueCore::setDefaultMaxBufferCountLocked(int count) { - const int minBufferCount = 2; - if (count < minBufferCount || count > GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGV("setDefaultMaxBufferCount: invalid count %d, should be in " - "[%d, %d]", - count, minBufferCount, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - ALOGV("setDefaultMaxBufferCount: setting count to %d", count); - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -void GonkBufferQueueCore::freeBufferLocked(int slot) { - ALOGV("freeBufferLocked: slot %d", slot); - - if (mSlots[slot].mTextureClient) { - mSlots[slot].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr<TextureClientReleaseTask> task = - MakeAndAddRef<TextureClientReleaseTask>(mSlots[slot].mTextureClient); - mSlots[slot].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - mSlots[slot].mGraphicBuffer.clear(); - if (mSlots[slot].mBufferState == GonkBufferSlot::ACQUIRED) { - mSlots[slot].mNeedsCleanupOnRelease = true; - } - mSlots[slot].mBufferState = GonkBufferSlot::FREE; - mSlots[slot].mFrameNumber = UINT32_MAX; - mSlots[slot].mAcquireCalled = false; - - // Destroy fence as GonkBufferQueue now takes ownership - mSlots[slot].mFence = Fence::NO_FENCE; -} - -void GonkBufferQueueCore::freeAllBuffersLocked() { - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - freeBufferLocked(s); - } -} - -bool GonkBufferQueueCore::stillTracking(const GonkBufferItem* item) const { - const GonkBufferSlot& slot = mSlots[item->mSlot]; - - ALOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } " - "slot { slot=%d/%" PRIu64 " buffer=%p }", - item->mSlot, item->mFrameNumber, - (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), - item->mSlot, slot.mFrameNumber, - (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); - - // Compare item with its original buffer slot. We can check the slot as - // the buffer would not be moved to a different slot by the producer. - return (slot.mGraphicBuffer != NULL) && - (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); -} - -void GonkBufferQueueCore::waitWhileAllocatingLocked() const { - ATRACE_CALL(); - while (mIsAllocating) { - mIsAllocatingCondition.wait(mMutex); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h deleted file mode 100644 index 936e11686..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUECORE_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUECORE_LL_H - -#include "GonkBufferQueueDefs.h" -#include "GonkBufferSlot.h" - -#include <utils/Condition.h> -#include <utils/Mutex.h> -#include <utils/NativeHandle.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/StrongPointer.h> -#include <utils/Trace.h> -#include <utils/Vector.h> - -#include "mozilla/layers/TextureClient.h" - -#define ATRACE_BUFFER_INDEX(index) - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace android { - -class GonkBufferItem; -class IConsumerListener; -class IGraphicBufferAlloc; -class IProducerListener; - -class GonkBufferQueueCore : public virtual RefBase { - - friend class GonkBufferQueueProducer; - friend class GonkBufferQueueConsumer; - -public: - // Used as a placeholder slot number when the value isn't pointing to an - // existing buffer. - enum { INVALID_BUFFER_SLOT = -1 }; // TODO: Extract from IGBC::BufferItem - - // We reserve two slots in order to guarantee that the producer and - // consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = GonkBufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; - - // The default API number used to indicate that no producer is connected - enum { NO_CONNECTED_API = 0 }; - - typedef Vector<GonkBufferItem> Fifo; - typedef mozilla::layers::TextureClient TextureClient; - - // GonkBufferQueueCore manages a pool of gralloc memory slots to be used by - // producers and consumers. allocator is used to allocate all the needed - // gralloc buffers. - GonkBufferQueueCore(const sp<IGraphicBufferAlloc>& allocator = NULL); - virtual ~GonkBufferQueueCore(); - -private: - // Dump our state in a string - void dump(String8& result, const char* prefix) const; - - int getSlotFromTextureClientLocked(TextureClient* client) const; - - // getMinUndequeuedBufferCountLocked returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. The async parameter - // tells whether we're in asynchronous mode. - int getMinUndequeuedBufferCountLocked(bool async) const; - - // getMinMaxBufferCountLocked returns the minimum number of buffers allowed - // given the current GonkBufferQueue state. The async parameter tells whether - // we're in asynchonous mode. - int getMinMaxBufferCountLocked(bool async) const; - - // getMaxBufferCountLocked returns the maximum number of buffers that can be - // allocated at once. This value depends on the following member variables: - // - // mDequeueBufferCannotBlock - // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // async parameter - // - // Any time one of these member variables is changed while a producer is - // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked(bool async) const; - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The - // initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); - - // freeBufferLocked frees the GraphicBuffer and sync resources for the - // given slot. - void freeBufferLocked(int slot); - - // freeAllBuffersLocked frees the GraphicBuffer and sync resources for - // all slots. - void freeAllBuffersLocked(); - - // stillTracking returns true iff the buffer item is still being tracked - // in one of the slots. - bool stillTracking(const GonkBufferItem* item) const; - - // waitWhileAllocatingLocked blocks until mIsAllocating is false. - void waitWhileAllocatingLocked() const; - - // mAllocator is the connection to SurfaceFlinger that is used to allocate - // new GraphicBuffer objects. - sp<IGraphicBufferAlloc> mAllocator; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkBufferQueueCore objects. It must be locked whenever any - // member variable is accessed. - mutable Mutex mMutex; - - // mIsAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume image buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A GonkBufferQueue that is abandoned will return - // the NO_INIT error from all IGraphicBufferProducer methods capable of - // returning an error. - bool mIsAbandoned; - - // mConsumerControlledByApp indicates whether the connected consumer is - // controlled by the application. - bool mConsumerControlledByApp; - - // mConsumerName is a string used to identify the GonkBufferQueue in log - // messages. It is set by the IGraphicBufferConsumer::setConsumerName - // method. - String8 mConsumerName; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially - // set to NULL and is written by consumerConnect and consumerDisconnect. - sp<IConsumerListener> mConsumerListener; - - // mConsumerUsageBits contains flags that the consumer wants for - // GraphicBuffers. - uint32_t mConsumerUsageBits; - - // mConnectedApi indicates the producer API that is currently connected - // to this GonkBufferQueue. It defaults to NO_CONNECTED_API, and gets updated - // by the connect and disconnect methods. - int mConnectedApi; - - // mConnectedProducerToken is used to set a binder death notification on - // the producer. - sp<IProducerListener> mConnectedProducerListener; - - // mSlots is an array of buffer slots that must be mirrored on the producer - // side. This allows buffer ownership to be transferred between the producer - // and consumer without sending a GraphicBuffer over Binder. The entire - // array is initialized to NULL at construction time, and buffers are - // allocated for a slot when requestBuffer is called with that slot's index. - GonkBufferQueueDefs::SlotsType mSlots; - - // mQueue is a FIFO of queued buffers used in synchronous mode. - Fifo mQueue; - - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the producer by calling - // setBufferCount. The default is 0, which means that the producer doesn't - // care about the number of buffers in the pool. In that case, - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - - // mDequeueCondition is a condition variable used for dequeueBuffer in - // synchronous mode. - mutable Condition mDequeueCondition; - - // mUseAsyncBuffer indicates whether an extra buffer is used in async mode - // to prevent dequeueBuffer from blocking. - bool mUseAsyncBuffer; - - // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to - // block. This flag is set during connect when both the producer and - // consumer are controlled by the application. - bool mDequeueBufferCannotBlock; - - // mDefaultBufferFormat can be set so it will override the buffer format - // when it isn't specified in dequeueBuffer. - uint32_t mDefaultBufferFormat; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in dequeueBuffer if a width and height of 0 are specified. - int mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in dequeueBuffer if a width and height of 0 are specified. - int mDefaultHeight; - - // mDefaultMaxBufferCount is the default limit on the number of buffers that - // will be allocated at one time. This default limit is set by the consumer. - // The limit (as opposed to the default limit) may be overriden by the - // producer. - int mDefaultMaxBufferCount; - - // mMaxAcquiredBufferCount is the number of buffers that the consumer may - // acquire at one time. It defaults to 1, and can be changed by the consumer - // via setMaxAcquiredBufferCount, but this may only be done while no - // producer is connected to the GonkBufferQueue. This value is used to derive - // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. - int mMaxAcquiredBufferCount; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is reset - // when something causes all buffers to be freed (e.g., changing the buffer - // count). - bool mBufferHasBeenQueued; - - // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call and buffer allocation. - uint64_t mFrameCounter; - - // mTransformHint is used to optimize for screen rotations. - uint32_t mTransformHint; - - // mSidebandStream is a handle to the sideband buffer stream, if any - sp<NativeHandle> mSidebandStream; - - // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which - // releases mMutex while doing the allocation proper). Producers should not modify any of the - // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to - // false. - bool mIsAllocating; - - // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating - // becomes false. - mutable Condition mIsAllocatingCondition; -}; // class GonkBufferQueueCore - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h deleted file mode 100644 index 60085706f..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_BUFFERQUEUECOREDEFS_H -#define NATIVEWINDOW_BUFFERQUEUECOREDEFS_H - -#include "GonkBufferSlot.h" - -namespace android { - class GonkBufferQueueCore; - - namespace GonkBufferQueueDefs { - // GonkBufferQueue will keep track of at most this value of buffers. - // Attempts at runtime to increase the number of buffers past this - // will fail. - enum { NUM_BUFFER_SLOTS = 64 }; - - typedef GonkBufferSlot SlotsType[NUM_BUFFER_SLOTS]; - } // namespace GonkBufferQueueDefs -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp deleted file mode 100644 index 649d06bee..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_NDEBUG 0 - -#include "GonkBufferQueue.h" -#include "GonkBufferQueueConsumer.h" -#include "GonkBufferQueueCore.h" -#include "GonkBufferQueueProducer.h" - -namespace android { - -GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp<ConsumerListener>& consumerListener): - mConsumerListener(consumerListener) {} - -GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -#if ANDROID_VERSION == 21 -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} -#else -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable(const ::android::BufferItem& item) { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(item); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onFrameReplaced(const ::android::BufferItem& item) { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameReplaced(item); - } -} -#endif - -void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { - sp<ConsumerListener> listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onSidebandStreamChanged(); - } -} - -void GonkBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, - sp<IGonkGraphicBufferConsumer>* outConsumer, - const sp<IGraphicBufferAlloc>& allocator) { - LOG_ALWAYS_FATAL_IF(outProducer == NULL, - "GonkBufferQueue: outProducer must not be NULL"); - LOG_ALWAYS_FATAL_IF(outConsumer == NULL, - "GonkBufferQueue: outConsumer must not be NULL"); - - sp<GonkBufferQueueCore> core(new GonkBufferQueueCore(allocator)); - LOG_ALWAYS_FATAL_IF(core == NULL, - "GonkBufferQueue: failed to create GonkBufferQueueCore"); - - sp<IGraphicBufferProducer> producer(new GonkBufferQueueProducer(core)); - LOG_ALWAYS_FATAL_IF(producer == NULL, - "GonkBufferQueue: failed to create GonkBufferQueueProducer"); - - sp<IGonkGraphicBufferConsumer> consumer(new GonkBufferQueueConsumer(core)); - LOG_ALWAYS_FATAL_IF(consumer == NULL, - "GonkBufferQueue: failed to create GonkBufferQueueConsumer"); - - *outProducer = producer; - *outConsumer = consumer; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h deleted file mode 100644 index b1b4e06b5..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUE_LL_H - -#include "GonkBufferQueueDefs.h" -#include "IGonkGraphicBufferConsumerLL.h" -#include <gui/IGraphicBufferProducer.h> -#include <gui/IConsumerListener.h> - -// These are only required to keep other parts of the framework with incomplete -// dependencies building successfully -#include <gui/IGraphicBufferAlloc.h> - -namespace android { - -class GonkBufferQueue { -public: - // GonkBufferQueue will keep track of at most this value of buffers. - // Attempts at runtime to increase the number of buffers past this will fail. - enum { NUM_BUFFER_SLOTS = GonkBufferQueueDefs::NUM_BUFFER_SLOTS }; - // Used as a placeholder slot# when the value isn't pointing to an existing buffer. - enum { INVALID_BUFFER_SLOT = IGonkGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT }; - // Alias to <IGonkGraphicBufferConsumer.h> -- please scope from there in future code! - enum { - NO_BUFFER_AVAILABLE = IGonkGraphicBufferConsumer::NO_BUFFER_AVAILABLE, - PRESENT_LATER = IGonkGraphicBufferConsumer::PRESENT_LATER, - }; - - // When in async mode we reserve two slots in order to guarantee that the - // producer and consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - - // for backward source compatibility - typedef ::android::ConsumerListener ConsumerListener; - typedef IGonkGraphicBufferConsumer::BufferItem BufferItem; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // GonkBufferQueue object and the consumer object. The reason this can't be a weak - // reference in the GonkBufferQueue class is because we're planning to expose the - // consumer side of a GonkBufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public BnConsumerListener { - public: - ProxyConsumerListener(const wp<ConsumerListener>& consumerListener); - virtual ~ProxyConsumerListener(); -#if ANDROID_VERSION == 21 - virtual void onFrameAvailable(); -#else - virtual void onFrameAvailable(const ::android::BufferItem& item); - virtual void onFrameReplaced(const ::android::BufferItem& item); -#endif - virtual void onBuffersReleased(); - virtual void onSidebandStreamChanged(); - private: - // mConsumerListener is a weak reference to the IConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp<ConsumerListener> mConsumerListener; - }; - - // GonkBufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allocator is used to allocate all the - // needed gralloc buffers. - static void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, - sp<IGonkGraphicBufferConsumer>* outConsumer, - const sp<IGraphicBufferAlloc>& allocator = NULL); - -private: - GonkBufferQueue(); // Create through createBufferQueue -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKBUFFERQUEUE_LL_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp deleted file mode 100644 index d3436756f..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp +++ /dev/null @@ -1,886 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include <inttypes.h> - -#define LOG_TAG "GonkBufferQueueProducer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "GonkBufferItem.h" -#include "GonkBufferQueueCore.h" -#include "GonkBufferQueueProducer.h" -#include <gui/IConsumerListener.h> -#include <gui/IGraphicBufferAlloc.h> -#include <gui/IProducerListener.h> - -#include <cutils/compiler.h> -#include <utils/Log.h> -#include <utils/Trace.h> - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/layers/TextureClient.h" - -namespace android { - -GonkBufferQueueProducer::GonkBufferQueueProducer(const sp<GonkBufferQueueCore>& core) : - mCore(core), - mSlots(core->mSlots), - mConsumerName(), - mSynchronousMode(true), - mStickyTransform(0) {} - -GonkBufferQueueProducer::~GonkBufferQueueProducer() {} - -status_t GonkBufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { - ATRACE_CALL(); - ALOGV("requestBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("requestBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("requestBuffer: slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("requestBuffer: slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::setBufferCount(int bufferCount) { - ATRACE_CALL(); - ALOGV("setBufferCount: count = %d", bufferCount); - - sp<IConsumerListener> listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (mCore->mIsAbandoned) { - ALOGE("setBufferCount: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (bufferCount > GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("setBufferCount: bufferCount %d too large (max %d)", - bufferCount, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - // There must be no dequeued buffers when changing the buffer count. - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::DEQUEUED) { - ALOGE("setBufferCount: buffer owned by producer"); - return BAD_VALUE; - } - } - - if (bufferCount == 0) { - mCore->mOverrideMaxBufferCount = 0; - mCore->mDequeueCondition.broadcast(); - return NO_ERROR; - } - - const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false); - if (bufferCount < minBufferSlots) { - ALOGE("setBufferCount: requested buffer count %d is less than " - "minimum %d", bufferCount, minBufferSlots); - return BAD_VALUE; - } - - // Here we are guaranteed that the producer doesn't have any dequeued - // buffers and will release all of its buffer references. We don't - // clear the queue, however, so that currently queued buffers still - // get displayed. - mCore->freeAllBuffersLocked(); - mCore->mOverrideMaxBufferCount = bufferCount; - mCore->mDequeueCondition.broadcast(); - listener = mCore->mConsumerListener; - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, - bool async, int* found, status_t* returnFlags) const { - bool tryAgain = true; - while (tryAgain) { - if (mCore->mIsAbandoned) { - ALOGE("%s: GonkBufferQueue has been abandoned", caller); - return NO_INIT; - } - - const int maxBufferCount = mCore->getMaxBufferCountLocked(async); - if (async && mCore->mOverrideMaxBufferCount) { - // FIXME: Some drivers are manually setting the buffer count - // (which they shouldn't), so we do this extra test here to - // handle that case. This is TEMPORARY until we get this fixed. - if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("%s: async mode is invalid with buffer count override", - caller); - return BAD_VALUE; - } - } - - // Free up any buffers that are in slots beyond the max buffer count - //for (int s = maxBufferCount; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - // assert(mSlots[s].mBufferState == GonkBufferSlot::FREE); - // if (mSlots[s].mGraphicBuffer != NULL) { - // mCore->freeBufferLocked(s); - // *returnFlags |= RELEASE_ALL_BUFFERS; - // } - //} - - // Look for a free buffer to give to the client - *found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - int dequeuedCount = 0; - int acquiredCount = 0; - for (int s = 0; s < maxBufferCount; ++s) { - switch (mSlots[s].mBufferState) { - case GonkBufferSlot::DEQUEUED: - ++dequeuedCount; - break; - case GonkBufferSlot::ACQUIRED: - ++acquiredCount; - break; - case GonkBufferSlot::FREE: - // We return the oldest of the free buffers to avoid - // stalling the producer if possible, since the consumer - // may still have pending reads of in-flight buffers - if (*found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { - *found = s; - } - break; - default: - break; - } - } - - // Producers are not allowed to dequeue more than one buffer if they - // did not set a buffer count - if (!mCore->mOverrideMaxBufferCount && dequeuedCount) { - ALOGE("%s: can't dequeue multiple buffers without setting the " - "buffer count", caller); - return INVALID_OPERATION; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below - if (mCore->mBufferHasBeenQueued) { - // Make sure the producer is not trying to dequeue more buffers - // than allowed - const int newUndequeuedCount = - maxBufferCount - (dequeuedCount + 1); - const int minUndequeuedCount = - mCore->getMinUndequeuedBufferCountLocked(async); - if (newUndequeuedCount < minUndequeuedCount) { - ALOGE("%s: min undequeued buffer count (%d) exceeded " - "(dequeued=%d undequeued=%d)", - caller, minUndequeuedCount, - dequeuedCount, newUndequeuedCount); - return INVALID_OPERATION; - } - } - - // If we disconnect and reconnect quickly, we can be in a state where - // our slots are empty but we have many buffers in the queue. This can - // cause us to run out of memory if we outrun the consumer. Wait here if - // it looks like we have too many buffers queued up. - bool tooManyBuffers = mCore->mQueue.size() - > static_cast<size_t>(maxBufferCount); - if (tooManyBuffers) { - ALOGV("%s: queue size is %zu, waiting", caller, - mCore->mQueue.size()); - } - - // If no buffer is found, or if the queue has too many buffers - // outstanding, wait for a buffer to be acquired or released, or for the - // max buffer count to change. - tryAgain = (*found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) || - tooManyBuffers; - if (tryAgain) { - // Return an error if we're in non-blocking mode (producer and - // consumer are controlled by the application). - // However, the consumer is allowed to briefly acquire an extra - // buffer (which could cause us to have to wait here), which is - // okay, since it is only used to implement an atomic acquire + - // release (e.g., in GLConsumer::updateTexImage()) - if (mCore->mDequeueBufferCannotBlock && - (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { - return WOULD_BLOCK; - } - mCore->mDequeueCondition.wait(mCore->mMutex); - } - } // while (tryAgain) - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::dequeueBuffer(int *outSlot, - sp<android::Fence> *outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { - ATRACE_CALL(); - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mConsumerName = mCore->mConsumerName; - } // Autolock scope - - ALOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", - async ? "true" : "false", width, height, format, usage); - - if ((width && !height) || (!width && height)) { - ALOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); - return BAD_VALUE; - } - - status_t returnFlags = NO_ERROR; - // Reset slot - *outSlot = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - - bool attachedByConsumer = false; - - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (format == 0) { - format = mCore->mDefaultBufferFormat; - } - - // Enable the usage bits the consumer requested - usage |= mCore->mConsumerUsageBits; - - int found; - status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; - } - - // This should not happen - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - ALOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - *outSlot = found; - - attachedByConsumer = mSlots[found].mAttachedByConsumer; - - const bool useDefaultSize = !width && !height; - if (useDefaultSize) { - width = mCore->mDefaultWidth; - height = mCore->mDefaultHeight; - } - - mSlots[found].mBufferState = GonkBufferSlot::DEQUEUED; - - const sp<GraphicBuffer>& buffer(mSlots[found].mGraphicBuffer); - if ((buffer == NULL) || - (static_cast<uint32_t>(buffer->width) != width) || - (static_cast<uint32_t>(buffer->height) != height) || - (static_cast<uint32_t>(buffer->format) != format) || - ((static_cast<uint32_t>(buffer->usage) & usage) != usage)) - { - mSlots[found].mAcquireCalled = false; - mSlots[found].mGraphicBuffer = NULL; - mSlots[found].mRequestBufferCalled = false; - mSlots[found].mFence = Fence::NO_FENCE; - - if (mSlots[found].mTextureClient) { - mSlots[found].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr<TextureClientReleaseTask> task = - MakeAndAddRef<TextureClientReleaseTask>(mSlots[found].mTextureClient); - mSlots[found].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - - returnFlags |= BUFFER_NEEDS_REALLOCATION; - } - - if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { - ALOGE("dequeueBuffer: about to return a NULL fence - " - "slot=%d w=%d h=%d format=%u", - found, buffer->width, buffer->height, buffer->format); - } - - *outFence = mSlots[found].mFence; - mSlots[found].mFence = Fence::NO_FENCE; - } // Autolock scope - - if (returnFlags & BUFFER_NEEDS_REALLOCATION) { - RefPtr<LayersIPCChannel> allocator = ImageBridgeChild::GetSingleton(); - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - GrallocTextureData* texData = GrallocTextureData::Create(IntSize(width,height), format, - gfx::BackendType::NONE, - usage, allocator); - if (!texData) { - ALOGE("dequeueBuffer: failed to alloc gralloc buffer"); - return -ENOMEM; - } - RefPtr<TextureClient> textureClient = TextureClient::CreateWithData( - texData, TextureFlags::RECYCLE | TextureFlags::DEALLOCATE_CLIENT, allocator); - - sp<GraphicBuffer> graphicBuffer = texData->GetGraphicBuffer(); - - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("dequeueBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - mSlots[*outSlot].mFrameNumber = UINT32_MAX; - mSlots[*outSlot].mGraphicBuffer = graphicBuffer; - mSlots[*outSlot].mTextureClient = textureClient; - } // Autolock scope - } - - if (attachedByConsumer) { - returnFlags |= BUFFER_NEEDS_REALLOCATION; - } - - ALOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", - *outSlot, - mSlots[*outSlot].mFrameNumber, - mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t GonkBufferQueueProducer::detachBuffer(int slot) { - ATRACE_CALL(); - ATRACE_BUFFER_INDEX(slot); - ALOGV("detachBuffer(P): slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("detachBuffer(P): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("detachBuffer(P): slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("detachBuffer(P): slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } else if (!mSlots[slot].mRequestBufferCalled) { - ALOGE("detachBuffer(P): buffer in slot %d has not been requested", - slot); - return BAD_VALUE; - } - - mCore->freeBufferLocked(slot); - mCore->mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence) { - ATRACE_CALL(); - - if (outBuffer == NULL) { - ALOGE("detachNextBuffer: outBuffer must not be NULL"); - return BAD_VALUE; - } else if (outFence == NULL) { - ALOGE("detachNextBuffer: outFence must not be NULL"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (mCore->mIsAbandoned) { - ALOGE("detachNextBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - // Find the oldest valid slot - int found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::FREE && - mSlots[s].mGraphicBuffer != NULL) { - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } - } - } - - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - return NO_MEMORY; - } - - ALOGV("detachNextBuffer detached slot %d", found); - - *outBuffer = mSlots[found].mGraphicBuffer; - *outFence = mSlots[found].mFence; - mCore->freeBufferLocked(found); - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::attachBuffer(int* outSlot, - const sp<android::GraphicBuffer>& buffer) { - ATRACE_CALL(); - - if (outSlot == NULL) { - ALOGE("attachBuffer(P): outSlot must not be NULL"); - return BAD_VALUE; - } else if (buffer == NULL) { - ALOGE("attachBuffer(P): cannot attach NULL buffer"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - status_t returnFlags = NO_ERROR; - int found; - // TODO: Should we provide an async flag to attachBuffer? It seems - // unlikely that buffers which we are attaching to a GonkBufferQueue will - // be asynchronous (droppable), but it may not be impossible. - status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; - } - - // This should not happen - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - ALOGE("attachBuffer(P): no available buffer slots"); - return -EBUSY; - } - - *outSlot = found; - ATRACE_BUFFER_INDEX(*outSlot); - ALOGV("attachBuffer(P): returning slot %d flags=%#x", - *outSlot, returnFlags); - - mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState = GonkBufferSlot::DEQUEUED; - mSlots[*outSlot].mFence = Fence::NO_FENCE; - mSlots[*outSlot].mRequestBufferCalled = true; - - return returnFlags; -} - -status_t GonkBufferQueueProducer::setSynchronousMode(bool enabled) { - ALOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mSynchronousMode != enabled) { - mSynchronousMode = enabled; - mCore->mDequeueCondition.broadcast(); - } - return OK; -} - -status_t GonkBufferQueueProducer::queueBuffer(int slot, - const QueueBufferInput &input, QueueBufferOutput *output) { - ATRACE_CALL(); - - int64_t timestamp; - bool isAutoTimestamp; - Rect crop; - int scalingMode; - uint32_t transform; - uint32_t stickyTransform; - bool async; - sp<Fence> fence; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence, &stickyTransform); - - if (fence == NULL) { - ALOGE("queueBuffer: fence is NULL"); - // Temporary workaround for b/17946343: soldier-on instead of returning an error. This - // prevents the client from dying, at the risk of visible corruption due to hwcomposer - // reading the buffer before the producer is done rendering it. Unless the buffer is the - // last frame of an animation, the corruption will be transient. - fence = Fence::NO_FENCE; - // return BAD_VALUE; - } - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: - break; - default: - ALOGE("queueBuffer: unknown scaling mode %d", scalingMode); - return BAD_VALUE; - } - - GonkBufferItem item; - sp<IConsumerListener> listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("queueBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - const int maxBufferCount = mCore->getMaxBufferCountLocked(async); - if (async && mCore->mOverrideMaxBufferCount) { - // FIXME: Some drivers are manually setting the buffer count - // (which they shouldn't), so we do this extra test here to - // handle that case. This is TEMPORARY until we get this fixed. - if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("queueBuffer: async mode is invalid with " - "buffer count override"); - return BAD_VALUE; - } - } - - if (slot < 0 || slot >= maxBufferCount) { - ALOGE("queueBuffer: slot index %d out of range [0, %d)", - slot, maxBufferCount); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("queueBuffer: slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } else if (!mSlots[slot].mRequestBufferCalled) { - ALOGE("queueBuffer: slot %d was queued without requesting " - "a buffer", slot); - return BAD_VALUE; - } - - ALOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 - " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, timestamp, - crop.left, crop.top, crop.right, crop.bottom, - transform, GonkBufferItem::scalingModeName(scalingMode)); - - const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedRect; - crop.intersect(bufferRect, &croppedRect); - if (croppedRect != crop) { - ALOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", slot); - return BAD_VALUE; - } - - mSlots[slot].mFence = fence; - mSlots[slot].mBufferState = GonkBufferSlot::QUEUED; - ++mCore->mFrameCounter; - mSlots[slot].mFrameNumber = mCore->mFrameCounter; - - item.mAcquireCalled = mSlots[slot].mAcquireCalled; - item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; - item.mCrop = crop; - item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; - item.mTransformToDisplayInverse = - bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); - item.mScalingMode = scalingMode; - item.mTimestamp = timestamp; - item.mIsAutoTimestamp = isAutoTimestamp; - item.mFrameNumber = mCore->mFrameCounter; - item.mSlot = slot; - item.mFence = fence; - item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; - - mStickyTransform = stickyTransform; - - if (mCore->mQueue.empty()) { - // When the queue is empty, we can ignore mDequeueBufferCannotBlock - // and simply queue this buffer - mCore->mQueue.push_back(item); - listener = mCore->mConsumerListener; - } else { - // When the queue is not empty, we need to look at the front buffer - // state to see if we need to replace it - GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - if (front->mIsDroppable || !mSynchronousMode) { - // If the front queued buffer is still being tracked, we first - // mark it as freed - if (mCore->stillTracking(front)) { - mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE; - // Reset the frame number of the freed buffer so that it is - // the first in line to be dequeued again - mSlots[front->mSlot].mFrameNumber = 0; - } - // Overwrite the droppable buffer with the incoming one - *front = item; - listener = mCore->mConsumerListener; - } else { - mCore->mQueue.push_back(item); - listener = mCore->mConsumerListener; - } - } - - mCore->mBufferHasBeenQueued = true; - mCore->mDequeueCondition.broadcast(); - - output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); - - item.mGraphicBuffer.clear(); - item.mSlot = GonkBufferItem::INVALID_BUFFER_SLOT; - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { -#if ANDROID_VERSION == 21 - listener->onFrameAvailable(); -#else - listener->onFrameAvailable(reinterpret_cast<::android::BufferItem&>(item)); -#endif - } - - return NO_ERROR; -} - -void GonkBufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) { - ATRACE_CALL(); - ALOGV("cancelBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("cancelBuffer: GonkBufferQueue has been abandoned"); - return; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("cancelBuffer: slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("cancelBuffer: slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return; - } else if (fence == NULL) { - ALOGE("cancelBuffer: fence is NULL"); - return; - } - - mSlots[slot].mBufferState = GonkBufferSlot::FREE; - mSlots[slot].mFrameNumber = 0; - mSlots[slot].mFence = fence; - mCore->mDequeueCondition.broadcast(); -} - -int GonkBufferQueueProducer::query(int what, int *outValue) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - - if (outValue == NULL) { - ALOGE("query: outValue was NULL"); - return BAD_VALUE; - } - - if (mCore->mIsAbandoned) { - ALOGE("query: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mCore->mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mCore->mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mCore->mDefaultBufferFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mCore->getMinUndequeuedBufferCountLocked(false); - break; - case NATIVE_WINDOW_STICKY_TRANSFORM: - value = static_cast<int>(mStickyTransform); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mCore->mQueue.size() > 1); - break; - case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - value = mCore->mConsumerUsageBits; - break; - default: - return BAD_VALUE; - } - - ALOGV("query: %d? %d", what, value); - *outValue = value; - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::connect(const sp<IProducerListener>& listener, - int api, bool producerControlledByApp, QueueBufferOutput *output) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - mConsumerName = mCore->mConsumerName; - ALOGV("connect(P): api=%d producerControlledByApp=%s", api, - producerControlledByApp ? "true" : "false"); - - if (mCore->mIsAbandoned) { - ALOGE("connect(P): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (mCore->mConsumerListener == NULL) { - ALOGE("connect(P): GonkBufferQueue has no consumer"); - return NO_INIT; - } - - if (output == NULL) { - ALOGE("connect(P): output was NULL"); - return BAD_VALUE; - } - - if (mCore->mConnectedApi != GonkBufferQueueCore::NO_CONNECTED_API) { - ALOGE("connect(P): already connected (cur=%d req=%d)", mCore->mConnectedApi, - api); - return BAD_VALUE; - } - - int status = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - mCore->mConnectedApi = api; - output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); - - // Set up a death notification so that we can disconnect - // automatically if the remote producer dies - if (listener != NULL && - listener->asBinder()->remoteBinder() != NULL) { - status = listener->asBinder()->linkToDeath( - static_cast<IBinder::DeathRecipient*>(this)); - if (status != NO_ERROR) { - ALOGE("connect(P): linkToDeath failed: %s (%d)", - strerror(-status), status); - } - } - mCore->mConnectedProducerListener = listener; - break; - default: - ALOGE("connect(P): unknown API %d", api); - status = BAD_VALUE; - break; - } - - mCore->mBufferHasBeenQueued = false; - mCore->mDequeueBufferCannotBlock = - mCore->mConsumerControlledByApp && producerControlledByApp; - - return status; -} - -status_t GonkBufferQueueProducer::disconnect(int api) { - ATRACE_CALL(); - ALOGV("disconnect(P): api %d", api); - - int status = NO_ERROR; - sp<IConsumerListener> listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (mCore->mIsAbandoned) { - // It's not really an error to disconnect after the surface has - // been abandoned; it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mCore->mConnectedApi == api) { - mCore->freeAllBuffersLocked(); - mCore->mConnectedApi = GonkBufferQueueCore::NO_CONNECTED_API; - mCore->mSidebandStream.clear(); - mCore->mDequeueCondition.broadcast(); - listener = mCore->mConsumerListener; - } else { - ALOGE("disconnect(P): connected to another API " - "(cur=%d req=%d)", mCore->mConnectedApi, api); - status = BAD_VALUE; - } - break; - default: - ALOGE("disconnect(P): unknown API %d", api); - status = BAD_VALUE; - break; - } - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return status; -} - -status_t GonkBufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) { - return INVALID_OPERATION; -} - -void GonkBufferQueueProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, uint32_t format, uint32_t usage) { - ALOGE("allocateBuffers: no op"); -} - -void GonkBufferQueueProducer::binderDied(const wp<android::IBinder>& /* who */) { - // If we're here, it means that a producer we were connected to died. - // We're guaranteed that we are still connected to it because we remove - // this callback upon disconnect. It's therefore safe to read mConnectedApi - // without synchronization here. - int api = mCore->mConnectedApi; - disconnect(api); -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h deleted file mode 100644 index a1a22416a..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUEPRODUCER_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUEPRODUCER_LL_H - -#include "GonkBufferQueueDefs.h" -#include <gui/IGraphicBufferProducer.h> - -namespace android { - -class GonkBufferQueueProducer : public BnGraphicBufferProducer, - private IBinder::DeathRecipient { -public: - friend class GonkBufferQueue; // Needed to access binderDied - - GonkBufferQueueProducer(const sp<GonkBufferQueueCore>& core); - virtual ~GonkBufferQueueProducer(); - - // requestBuffer returns the GraphicBuffer for slot N. - // - // In normal operation, this is called the first time slot N is returned - // by dequeueBuffer. It must be called again if dequeueBuffer returns - // flags indicating that previously-returned buffers are no longer valid. - virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the GonkBufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); - - // dequeueBuffer gets the next buffer slot index for the producer to use. - // If a buffer slot is available then that slot index is written to the - // location pointed to by the buf argument and a status of OK is returned. - // If no slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // - // The outFence parameter will be updated to hold the fence associated with - // the buffer. The contents of the buffer must not be overwritten until the - // fence signals. If the fence is Fence::NO_FENCE, the buffer may be - // written immediately. - // - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. If width and height are both zero, the - // default values specified by setDefaultBufferSize() are used instead. - // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. - // - // The usage argument specifies gralloc buffer usage flags. The values - // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These - // will be merged with the usage flags specified by setConsumerUsageBits. - // - // The return value may be a negative error value or a non-negative - // collection of flags. If the flags are set, the return values are - // valid, but additional actions must be performed. - // - // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the - // producer must discard cached GraphicBuffer references for the slot - // returned in buf. - // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer - // must discard cached GraphicBuffer references for all slots. - // - // In both cases, the producer will need to call requestBuffer to get a - // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *outSlot, sp<Fence>* outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); - - // See IGraphicBufferProducer::detachBuffer - virtual status_t detachBuffer(int slot); - - // See IGraphicBufferProducer::detachNextBuffer - virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence); - - // See IGraphicBufferProducer::attachBuffer - virtual status_t attachBuffer(int* outSlot, const sp<GraphicBuffer>& buffer); - - // queueBuffer returns a filled buffer to the GonkBufferQueue. - // - // Additional data is provided in the QueueBufferInput struct. Notably, - // a timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are producer-specific and should be documented by the - // producer. - // - // The caller may provide a fence that signals when all rendering - // operations have completed. Alternatively, NO_FENCE may be used, - // indicating that the buffer is ready immediately. - // - // Some values are returned in the output struct: the current settings - // for default width and height, the current transform hint, and the - // number of queued buffers. - virtual status_t queueBuffer(int slot, - const QueueBufferInput& input, QueueBufferOutput* output); - - // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't - // queue it for use by the consumer. - // - // The buffer will not be overwritten until the fence signals. The fence - // will usually be the one obtained from dequeueBuffer. - virtual void cancelBuffer(int slot, const sp<Fence>& fence); - - // Query native window attributes. The "what" values are enumerated in - // window.h (e.g. NATIVE_WINDOW_FORMAT). - virtual int query(int what, int* outValue); - - // connect attempts to connect a producer API to the GonkBufferQueue. This - // must be called before any other IGraphicBufferProducer methods are - // called except for getAllocator. A consumer must already be connected. - // - // This method will fail if connect was previously called on the - // GonkBufferQueue and no corresponding disconnect call was made (i.e. if - // it's still connected to a producer). - // - // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(const sp<IProducerListener>& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer API from the GonkBufferQueue. - // Calling this method will cause any subsequent calls to other - // IGraphicBufferProducer methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the GonkBufferQueue is not currently - // connected to the specified producer API. - virtual status_t disconnect(int api); - - // Attaches a sideband buffer stream to the IGraphicBufferProducer. - // - // A sideband stream is a device-specific mechanism for passing buffers - // from the producer to the consumer without using dequeueBuffer/ - // queueBuffer. If a sideband stream is present, the consumer can choose - // whether to acquire buffers from the sideband stream or from the queued - // buffers. - // - // Passing NULL or a different stream handle will detach the previous - // handle if any. - virtual status_t setSidebandStream(const sp<NativeHandle>& stream); - - // See IGraphicBufferProducer::allocateBuffers - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); - - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is synchronous. - // This should be called only during initialization. - virtual status_t setSynchronousMode(bool enabled); - -private: - // This is required by the IBinder::DeathRecipient interface - virtual void binderDied(const wp<IBinder>& who); - - // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may - // block if there are no available slots and we are not in non-blocking - // mode (producer and consumer controlled by the application). If it blocks, - // it will release mCore->mMutex while blocked so that other operations on - // the GonkBufferQueue may succeed. - status_t waitForFreeSlotThenRelock(const char* caller, bool async, - int* found, status_t* returnFlags) const; - - sp<GonkBufferQueueCore> mCore; - - // This references mCore->mSlots. Lock mCore->mMutex while accessing. - GonkBufferQueueDefs::SlotsType& mSlots; - - // This is a cached copy of the name stored in the GonkBufferQueueCore. - // It's updated during connect and dequeueBuffer (which should catch - // most updates). - String8 mConsumerName; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - uint32_t mStickyTransform; - -}; // class GonkBufferQueueProducer - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp deleted file mode 100644 index 9e4a424a9..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include "GonkBufferSlot.h" - -namespace android { - -const char* GonkBufferSlot::bufferStateName(BufferState state) { - switch (state) { - case GonkBufferSlot::DEQUEUED: return "DEQUEUED"; - case GonkBufferSlot::QUEUED: return "QUEUED"; - case GonkBufferSlot::FREE: return "FREE"; - case GonkBufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h deleted file mode 100644 index 759bb7b23..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERSLOT_LL_H -#define NATIVEWINDOW_GONKBUFFERSLOT_LL_H - -#include <ui/Fence.h> -#include <ui/GraphicBuffer.h> - -#include <utils/StrongPointer.h> - -#include "mozilla/layers/TextureClient.h" - -namespace android { - -struct GonkBufferSlot { - typedef mozilla::layers::TextureClient TextureClient; - - GonkBufferSlot() - : mBufferState(GonkBufferSlot::FREE), - mRequestBufferCalled(false), - mFrameNumber(0), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false), - mAttachedByConsumer(false) { - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp<GraphicBuffer> mGraphicBuffer; - - // BufferState represents the different states in which a buffer slot - // can be. All slots are initially FREE. - enum BufferState { - // FREE indicates that the buffer is available to be dequeued - // by the producer. The buffer may be in use by the consumer for - // a finite time, so the buffer must not be modified until the - // associated fence is signaled. - // - // The slot is "owned" by BufferQueue. It transitions to DEQUEUED - // when dequeueBuffer is called. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // producer, but has not yet been queued or canceled. The - // producer may modify the buffer's contents as soon as the - // associated ready fence is signaled. - // - // The slot is "owned" by the producer. It can transition to - // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been filled by the - // producer and queued for use by the consumer. The buffer - // contents may continue to be modified for a finite time, so - // the contents must not be accessed until the associated fence - // is signaled. - // - // The slot is "owned" by BufferQueue. It can transition to - // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is - // queued in asynchronous mode). - QUEUED = 2, - - // ACQUIRED indicates that the buffer has been acquired by the - // consumer. As with QUEUED, the contents must not be accessed - // by the consumer until the fence is signaled. - // - // The slot is "owned" by the consumer. It transitions to FREE - // when releaseBuffer is called. - ACQUIRED = 3 - }; - - static const char* bufferStateName(BufferState state); - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the producer did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching producer bugs. - bool mRequestBufferCalled; - - // mFrameNumber is the number of the queued frame for this slot. This - // is used to dequeue buffers in LRU order (useful because buffers - // may be released before their release fence is signaled). - uint64_t mFrameNumber; - - // mFence is a fence which will signal when work initiated by the - // previous owner of the buffer is finished. When the buffer is FREE, - // the fence indicates when the consumer has finished reading - // from the buffer, or when the producer has finished writing if it - // called cancelBuffer after queueing some writes. When the buffer is - // QUEUED, it indicates when the producer has finished filling the - // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been - // passed to the consumer or producer along with ownership of the - // buffer, and mFence is set to NO_FENCE. - sp<Fence> mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by the - // consumer. This is set when a buffer in ACQUIRED state is freed. - // It causes releaseBuffer to return STALE_BUFFER_SLOT. - bool mNeedsCleanupOnRelease; - - // Indicates whether the buffer was attached on the consumer side. - // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued - // to prevent the producer from using a stale cached buffer. - bool mAttachedByConsumer; - - // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. - RefPtr<TextureClient> mTextureClient; -}; - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp b/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp deleted file mode 100644 index 1ee37e4e2..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkConsumerBase" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define EGL_EGLEXT_PROTOTYPES - -#include <hardware/hardware.h> - -#include <gui/IGraphicBufferAlloc.h> -#include <utils/Log.h> -#include <utils/String8.h> - -#include "GonkConsumerBaseJB.h" - -// Macros for including the GonkConsumerBase name in log messages -#define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -GonkConsumerBase::GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue) : - mAbandoned(false), - mBufferQueue(bufferQueue) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp<GonkBufferQueue::ConsumerListener> listener; - sp<GonkBufferQueue::ConsumerListener> proxy; - listener = static_cast<GonkBufferQueue::ConsumerListener*>(this); - proxy = new GonkBufferQueue::ProxyConsumerListener(listener); - - status_t err = mBufferQueue->consumerConnect(proxy); - if (err != NO_ERROR) { - CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", - strerror(-err), err); - } else { - mBufferQueue->setConsumerName(mName); - } -} - -GonkConsumerBase::~GonkConsumerBase() { - CB_LOGV("~GonkConsumerBase"); - Mutex::Autolock lock(mMutex); - - // Verify that abandon() has been called before we get here. This should - // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a - // derived class to override that method and not call - // GonkConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); -} - -void GonkConsumerBase::onLastStrongRef(const void* id) { - abandon(); -} - -void GonkConsumerBase::freeBufferLocked(int slotIndex) { - CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = Fence::NO_FENCE; -} - -// Used for refactoring, should not be in final interface -sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue; -} - -void GonkConsumerBase::onFrameAvailable() { - CB_LOGV("onFrameAvailable"); - - sp<FrameAvailableListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); -#if ANDROID_VERSION == 17 - listener = mFrameAvailableListener; -#else - listener = mFrameAvailableListener.promote(); -#endif - } - - if (listener != NULL) { - CB_LOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void GonkConsumerBase::onBuffersReleased() { - Mutex::Autolock lock(mMutex); - - CB_LOGV("onBuffersReleased"); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint32_t mask = 0; - mBufferQueue->getReleasedBuffers(&mask); - for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } -} - -void GonkConsumerBase::abandon() { - CB_LOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - abandonLocked(); - mAbandoned = true; - } -} - -void GonkConsumerBase::abandonLocked() { - CB_LOGV("abandonLocked"); - for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - // disconnect from the GonkBufferQueue - mBufferQueue->consumerDisconnect(); - mBufferQueue.clear(); -} - -void GonkConsumerBase::setFrameAvailableListener( -#if ANDROID_VERSION == 17 - const sp<FrameAvailableListener>& listener) { -#else - const wp<FrameAvailableListener>& listener) { -#endif - CB_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void GonkConsumerBase::dump(String8& result) const { - char buffer[1024]; - dump(result, "", buffer, 1024); -} - -void GonkConsumerBase::dump(String8& result, const char* prefix, - char* buffer, size_t size) const { - Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix, buffer, size); -} - -void GonkConsumerBase::dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const { - snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned)); - result.append(buffer); - - if (!mAbandoned) { - mBufferQueue->dumpToString(result, prefix, buffer, SIZE); - } -} - -status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item) { - status_t err = mBufferQueue->acquireBuffer(item); - if (err != NO_ERROR) { - return err; - } - - if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; - } - - mSlots[item->mBuf].mFence = item->mFence; - - CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); - - return OK; -} - -status_t GonkConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) { - Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, fence); -} - -status_t GonkConsumerBase::addReleaseFenceLocked(int slot, const sp<Fence>& fence) { - CB_LOGV("addReleaseFenceLocked: slot=%d", slot); - - if (!mSlots[slot].mFence.get()) { - mSlots[slot].mFence = fence; - } else { - sp<Fence> mergedFence = Fence::merge( - String8::format("%.28s:%d", mName.string(), slot), - mSlots[slot].mFence, fence); - if (!mergedFence.get()) { - CB_LOGE("failed to merge release fences"); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - mSlots[slot].mFence = fence; - return BAD_VALUE; - } - mSlots[slot].mFence = mergedFence; - } - - return OK; -} - -status_t GonkConsumerBase::releaseBufferLocked(int slot) { - CB_LOGV("releaseBufferLocked: slot=%d", slot); - status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFence); - if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(slot); - } - - mSlots[slot].mFence = Fence::NO_FENCE; - - return err; -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseJB.h b/widget/gonk/nativewindow/GonkConsumerBaseJB.h deleted file mode 100644 index 8f523af37..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseJB.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKCONSUMERBASE_JB_H -#define NATIVEWINDOW_GONKCONSUMERBASE_JB_H - -#include <ui/GraphicBuffer.h> - -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -#include "GonkBufferQueueJB.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class String8; - -// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It -// handles common tasks like management of the connection to the GonkBufferQueue -// and the buffer pool. -class GonkConsumerBase : public virtual RefBase, - protected GonkBufferQueue::ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - virtual ~GonkConsumerBase(); - - // abandon frees all the buffers and puts the GonkConsumerBase into the - // 'abandoned' state. Once put in this state the GonkConsumerBase can never - // leave it. When in the 'abandoned' state, all methods of the - // IGraphicBufferProducer interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the GonkConsumerBase, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client - // or by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the GonkConsumerBase that will be used to identify it in - // log messages. - void setName(const String8& name); - - // getBufferQueue returns the GonkBufferQueue object to which this - // GonkConsumerBase is connected. - sp<GonkBufferQueue> getBufferQueue() const; - - // dump writes the current state to a string. Child classes should add - // their state to the dump by overriding the dumpLocked method, which is - // called by these methods after locking the mutex. - void dump(String8& result) const; - void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. -#if ANDROID_VERSION == 17 - void setFrameAvailableListener(const sp<FrameAvailableListener>& listener); -#else - void setFrameAvailableListener(const wp<FrameAvailableListener>& listener); -#endif - -private: - GonkConsumerBase(const GonkConsumerBase&); - void operator=(const GonkConsumerBase&); - -protected: - - // GonkConsumerBase constructs a new GonkConsumerBase object to consume image - // buffers from the given GonkBufferQueue. - GonkConsumerBase(const sp<GonkBufferQueue> &bufferQueue); - - // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that GonkConsumerBase - // can coordinate the clean-up by calling into virtual methods implemented - // by the derived classes. This would not be possible from the - // ConsuemrBase dtor because by the time that gets called the derived - // classes have already been destructed. - // - // This methods should not need to be overridden by derived classes, but - // if they are overridden the GonkConsumerBase implementation must be called - // from the derived class. - virtual void onLastStrongRef(const void* id); - - // Implementation of the GonkBufferQueue::ConsumerListener interface. These - // calls are used to notify the GonkConsumerBase of asynchronous events in the - // GonkBufferQueue. These methods should not need to be overridden by derived - // classes, but if they are overridden the GonkConsumerBase implementation - // must be called from the derived class. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot. Otherwise it has no effect. - // - // Derived classes should override this method to clean up any state they - // keep per slot. If it is overridden, the derived class's implementation - // must call GonkConsumerBase::freeBufferLocked. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex); - - // abandonLocked puts the GonkBufferQueue into the abandoned state, causing - // all future operations on it to fail. This method rather than the public - // abandon method should be overridden by child classes to add abandon- - // time behavior. - // - // Derived classes should override this method to clean up any object - // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call GonkConsumerBase::abandonLocked. - // - // This method must be called with mMutex locked. - virtual void abandonLocked(); - - // dumpLocked dumps the current state of the GonkConsumerBase object to the - // result string. Each line is prefixed with the string pointed to by the - // prefix argument. The buffer argument points to a buffer that may be - // used for intermediate formatting data, and the size of that buffer is - // indicated by the size argument. - // - // Derived classes should override this method to dump their internal - // state. If this method is overridden the derived class's implementation - // should call GonkConsumerBase::dumpLocked. - // - // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix, char* buffer, - size_t size) const; - - // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and - // updates the buffer slot for the buffer returned. - // - // Derived classes should override this method to perform any - // initialization that must take place the first time a buffer is assigned - // to a slot. If it is overridden the derived class's implementation must - // call GonkConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(GonkBufferQueue::BufferItem *item); - - // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the GonkBufferQueue. - // - // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the GonkBufferQueue. If - // it is overridden the derived class's implementation must call - // GonkConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int buf); - - // addReleaseFence* adds the sync points associated with a fence to the set - // of sync points that must be reached before the buffer in the given slot - // may be used after the slot has been released. This should be called by - // derived classes each time some asynchronous work is kicked off that - // references the buffer. - status_t addReleaseFence(int slot, const sp<Fence>& fence); - status_t addReleaseFenceLocked(int slot, const sp<Fence>& fence); - - // Slot contains the information and object references that - // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. - struct Slot { - // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if - // no Gralloc buffer is in the slot. - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence which will signal when the buffer associated with - // this buffer slot is no longer being used by the consumer and can be - // overwritten. The buffer can be dequeued before the fence signals; - // the producer is responsible for delaying writes until it signals. - sp<Fence> mFence; - }; - - // mSlots stores the buffers that have been allocated by the GonkBufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of GonkBufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume images buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the abandon - // method. A GonkBufferQueue that has been abandoned will return the NO_INIT - // error from all IGonkConsumerBase methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the GonkConsumerBase in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. -#if ANDROID_VERSION == 17 - sp<FrameAvailableListener> mFrameAvailableListener; -#else - wp<FrameAvailableListener> mFrameAvailableListener; -#endif - - // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object - // if none is supplied - sp<GonkBufferQueue> mBufferQueue; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkConsumerBase objects. It must be locked whenever the - // member variables are accessed or when any of the *Locked methods are - // called. - // - // This mutex is intended to be locked by derived classes. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKCONSUMERBASE_H diff --git a/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp b/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp deleted file mode 100644 index 3fc9fc16c..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkConsumerBase" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define EGL_EGLEXT_PROTOTYPES - -#include <hardware/hardware.h> - -#include <gui/IGraphicBufferAlloc.h> -#include <utils/Log.h> -#include <utils/String8.h> - -#include "GonkConsumerBaseKK.h" - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -GonkConsumerBase::GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue, bool controlledByApp) : - mAbandoned(false), - mConsumer(bufferQueue) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); - sp<IConsumerListener> proxy = new GonkBufferQueue::ProxyConsumerListener(listener); - - status_t err = mConsumer->consumerConnect(proxy, controlledByApp); - if (err != NO_ERROR) { - ALOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", - strerror(-err), err); - } else { - mConsumer->setConsumerName(mName); - } -} - -GonkConsumerBase::~GonkConsumerBase() { - ALOGV("~GonkConsumerBase"); - Mutex::Autolock lock(mMutex); - - // Verify that abandon() has been called before we get here. This should - // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a - // derived class to override that method and not call - // GonkConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); -} - -void GonkConsumerBase::onLastStrongRef(const void* id) { - abandon(); -} - -void GonkConsumerBase::freeBufferLocked(int slotIndex) { - ALOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = Fence::NO_FENCE; - mSlots[slotIndex].mFrameNumber = 0; -} - -// Used for refactoring, should not be in final interface -sp<GonkBufferQueue> GonkConsumerBase::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mConsumer; -} - -void GonkConsumerBase::onFrameAvailable() { - ALOGV("onFrameAvailable"); - - sp<FrameAvailableListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener.promote(); - } - - if (listener != NULL) { - ALOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void GonkConsumerBase::onBuffersReleased() { - Mutex::Autolock lock(mMutex); - - ALOGV("onBuffersReleased"); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint32_t mask = 0; - mConsumer->getReleasedBuffers(&mask); - for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } -} - -void GonkConsumerBase::abandon() { - ALOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - abandonLocked(); - mAbandoned = true; - } -} - -void GonkConsumerBase::abandonLocked() { - ALOGV("abandonLocked"); - for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - // disconnect from the BufferQueue - mConsumer->consumerDisconnect(); - mConsumer.clear(); -} - -void GonkConsumerBase::setFrameAvailableListener( - const wp<FrameAvailableListener>& listener) { - ALOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void GonkConsumerBase::dump(String8& result) const { - dump(result, ""); -} - -void GonkConsumerBase::dump(String8& result, const char* prefix) const { - Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix); -} - -void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); - - if (!mAbandoned) { - mConsumer->dumpToString(result, prefix); - } -} - -status_t GonkConsumerBase::acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); - if (err != NO_ERROR) { - return err; - } - - if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; - } - - mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; - mSlots[item->mBuf].mFence = item->mFence; - - ALOGV("acquireBufferLocked: -> slot=%d", item->mBuf); - - return OK; -} - -status_t GonkConsumerBase::addReleaseFence(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { - Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, graphicBuffer, fence); -} - -status_t GonkConsumerBase::addReleaseFenceLocked(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { - ALOGV("addReleaseFenceLocked: slot=%d", slot); - - // If consumer no longer tracks this graphicBuffer, we can safely - // drop this fence, as it will never be received by the producer. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - if (!mSlots[slot].mFence.get()) { - mSlots[slot].mFence = fence; - } else { - sp<Fence> mergedFence = Fence::merge( - String8::format("%.28s:%d", mName.string(), slot), - mSlots[slot].mFence, fence); - if (!mergedFence.get()) { - ALOGE("failed to merge release fences"); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - mSlots[slot].mFence = fence; - return BAD_VALUE; - } - mSlots[slot].mFence = mergedFence; - } - - return OK; -} - -status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) { - // If consumer no longer tracks this graphicBuffer (we received a new - // buffer on the same slot), the buffer producer is definitely no longer - // tracking it. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - ALOGV("releaseBufferLocked: slot=%d/%llu", - slot, mSlots[slot].mFrameNumber); - status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); - if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(slot); - } - - mSlots[slot].mFence = Fence::NO_FENCE; - - return err; -} - -bool GonkConsumerBase::stillTracking(int slot, - const sp<GraphicBuffer> graphicBuffer) { - if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { - return false; - } - return (mSlots[slot].mGraphicBuffer != NULL && - mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseKK.h b/widget/gonk/nativewindow/GonkConsumerBaseKK.h deleted file mode 100644 index e198ad843..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseKK.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKCONSUMERBASE_KK_H -#define NATIVEWINDOW_GONKCONSUMERBASE_KK_H - -#include <ui/GraphicBuffer.h> - -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> -#include <gui/IConsumerListener.h> - -#include "GonkBufferQueueKK.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class String8; - -// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It -// handles common tasks like management of the connection to the GonkBufferQueue -// and the buffer pool. -class GonkConsumerBase : public virtual RefBase, - protected ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - virtual ~GonkConsumerBase(); - - // abandon frees all the buffers and puts the GonkConsumerBase into the - // 'abandoned' state. Once put in this state the GonkConsumerBase can never - // leave it. When in the 'abandoned' state, all methods of the - // IGraphicBufferProducer interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the GonkConsumerBase, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client - // or by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the GonkConsumerBase that will be used to identify it in - // log messages. - void setName(const String8& name); - - // getBufferQueue returns the GonkBufferQueue object to which this - // GonkConsumerBase is connected. - sp<GonkBufferQueue> getBufferQueue() const; - - // dump writes the current state to a string. Child classes should add - // their state to the dump by overriding the dumpLocked method, which is - // called by these methods after locking the mutex. - void dump(String8& result) const; - void dump(String8& result, const char* prefix) const; - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const wp<FrameAvailableListener>& listener); - -private: - GonkConsumerBase(const GonkConsumerBase&); - void operator=(const GonkConsumerBase&); - -protected: - - // GonkConsumerBase constructs a new GonkConsumerBase object to consume image - // buffers from the given GonkBufferQueue. - GonkConsumerBase(const sp<GonkBufferQueue>& bufferQueue, bool controlledByApp = false); - - // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that GonkConsumerBase - // can coordinate the clean-up by calling into virtual methods implemented - // by the derived classes. This would not be possible from the - // ConsuemrBase dtor because by the time that gets called the derived - // classes have already been destructed. - // - // This methods should not need to be overridden by derived classes, but - // if they are overridden the GonkConsumerBase implementation must be called - // from the derived class. - virtual void onLastStrongRef(const void* id); - - // Implementation of the GonkBufferQueue::ConsumerListener interface. These - // calls are used to notify the GonkConsumerBase of asynchronous events in the - // GonkBufferQueue. These methods should not need to be overridden by derived - // classes, but if they are overridden the GonkConsumerBase implementation - // must be called from the derived class. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot. Otherwise it has no effect. - // - // Derived classes should override this method to clean up any state they - // keep per slot. If it is overridden, the derived class's implementation - // must call GonkConsumerBase::freeBufferLocked. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex); - - // abandonLocked puts the GonkBufferQueue into the abandoned state, causing - // all future operations on it to fail. This method rather than the public - // abandon method should be overridden by child classes to add abandon- - // time behavior. - // - // Derived classes should override this method to clean up any object - // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call GonkConsumerBase::abandonLocked. - // - // This method must be called with mMutex locked. - virtual void abandonLocked(); - - // dumpLocked dumps the current state of the GonkConsumerBase object to the - // result string. Each line is prefixed with the string pointed to by the - // prefix argument. The buffer argument points to a buffer that may be - // used for intermediate formatting data, and the size of that buffer is - // indicated by the size argument. - // - // Derived classes should override this method to dump their internal - // state. If this method is overridden the derived class's implementation - // should call GonkConsumerBase::dumpLocked. - // - // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix) const; - - // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and - // updates the buffer slot for the buffer returned. - // - // Derived classes should override this method to perform any - // initialization that must take place the first time a buffer is assigned - // to a slot. If it is overridden the derived class's implementation must - // call GonkConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen); - - // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the GonkBufferQueue. - // - // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the GonkBufferQueue. If - // it is overridden the derived class's implementation must call - // GonkConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer); - - // returns true iff the slot still has the graphicBuffer in it. - bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); - - // addReleaseFence* adds the sync points associated with a fence to the set - // of sync points that must be reached before the buffer in the given slot - // may be used after the slot has been released. This should be called by - // derived classes each time some asynchronous work is kicked off that - // references the buffer. - status_t addReleaseFence(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence); - status_t addReleaseFenceLocked(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence); - - // Slot contains the information and object references that - // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. - struct Slot { - // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if - // no Gralloc buffer is in the slot. - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence which will signal when the buffer associated with - // this buffer slot is no longer being used by the consumer and can be - // overwritten. The buffer can be dequeued before the fence signals; - // the producer is responsible for delaying writes until it signals. - sp<Fence> mFence; - - // the frame number of the last acquired frame for this slot - uint64_t mFrameNumber; - }; - - // mSlots stores the buffers that have been allocated by the GonkBufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of GonkBufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume images buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the abandon - // method. A GonkBufferQueue that has been abandoned will return the NO_INIT - // error from all IGonkConsumerBase methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the GonkConsumerBase in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - wp<FrameAvailableListener> mFrameAvailableListener; - - // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object - // if none is supplied - sp<GonkBufferQueue> mConsumer; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkConsumerBase objects. It must be locked whenever the - // member variables are accessed or when any of the *Locked methods are - // called. - // - // This mutex is intended to be locked by derived classes. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKCONSUMERBASE_H diff --git a/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp b/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp deleted file mode 100644 index 5b1166b57..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include <inttypes.h> - -#define LOG_TAG "GonkConsumerBase" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define EGL_EGLEXT_PROTOTYPES - -#include <hardware/hardware.h> - -#include <gui/IGraphicBufferAlloc.h> - -#include <utils/Log.h> -#include <utils/String8.h> - -#include "GonkConsumerBaseLL.h" - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -GonkConsumerBase::GonkConsumerBase(const sp<IGonkGraphicBufferConsumer>& bufferQueue, bool controlledByApp) : - mAbandoned(false), - mConsumer(bufferQueue) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this); - sp<IConsumerListener> proxy = new GonkBufferQueue::ProxyConsumerListener(listener); - - status_t err = mConsumer->consumerConnect(proxy, controlledByApp); - if (err != NO_ERROR) { - ALOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", - strerror(-err), err); - } else { - mConsumer->setConsumerName(mName); - } -} - -GonkConsumerBase::~GonkConsumerBase() { - ALOGV("~GonkConsumerBase"); - Mutex::Autolock lock(mMutex); - - // Verify that abandon() has been called before we get here. This should - // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a - // derived class to override that method and not call - // GonkConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); -} - -void GonkConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { - abandon(); -} - -void GonkConsumerBase::freeBufferLocked(int slotIndex) { - ALOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = Fence::NO_FENCE; - mSlots[slotIndex].mFrameNumber = 0; -} - -#if ANDROID_VERSION == 21 -void GonkConsumerBase::onFrameAvailable() { -#else -void GonkConsumerBase::onFrameAvailable(const ::android::BufferItem& item) { -#endif - ALOGV("onFrameAvailable"); - - sp<FrameAvailableListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener.promote(); - } - - if (listener != NULL) { - ALOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void GonkConsumerBase::onBuffersReleased() { - Mutex::Autolock lock(mMutex); - - ALOGV("onBuffersReleased"); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint64_t mask = 0; - mConsumer->getReleasedBuffers(&mask); - for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1ULL << i)) { - freeBufferLocked(i); - } - } -} - -void GonkConsumerBase::onSidebandStreamChanged() { -} - -void GonkConsumerBase::abandon() { - ALOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - abandonLocked(); - mAbandoned = true; - } -} - -void GonkConsumerBase::abandonLocked() { - ALOGV("abandonLocked"); - for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - // disconnect from the BufferQueue - mConsumer->consumerDisconnect(); - mConsumer.clear(); -} - -void GonkConsumerBase::setFrameAvailableListener( - const wp<FrameAvailableListener>& listener) { - ALOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void GonkConsumerBase::dump(String8& result) const { - dump(result, ""); -} - -void GonkConsumerBase::dump(String8& result, const char* prefix) const { - Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix); -} - -void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); - - if (!mAbandoned) { - mConsumer->dumpToString(result, prefix); - } -} - -status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); - if (err != NO_ERROR) { - return err; - } - - if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; - } - - mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; - mSlots[item->mBuf].mFence = item->mFence; - - ALOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, - item->mBuf, item->mFrameNumber); - - return OK; -} - -status_t GonkConsumerBase::addReleaseFence(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { - Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, graphicBuffer, fence); -} - -status_t GonkConsumerBase::addReleaseFenceLocked(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence) { - ALOGV("addReleaseFenceLocked: slot=%d", slot); - - // If consumer no longer tracks this graphicBuffer, we can safely - // drop this fence, as it will never be received by the producer. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - if (!mSlots[slot].mFence.get()) { - mSlots[slot].mFence = fence; - } else { - sp<Fence> mergedFence = Fence::merge( - String8::format("%.28s:%d", mName.string(), slot), - mSlots[slot].mFence, fence); - if (!mergedFence.get()) { - ALOGE("failed to merge release fences"); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - mSlots[slot].mFence = fence; - return BAD_VALUE; - } - mSlots[slot].mFence = mergedFence; - } - - return OK; -} - -status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer) { - // If consumer no longer tracks this graphicBuffer (we received a new - // buffer on the same slot), the buffer producer is definitely no longer - // tracking it. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - ALOGV("releaseBufferLocked: slot=%d/%" PRIu64, - slot, mSlots[slot].mFrameNumber); - status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); - if (err == IGonkGraphicBufferConsumer::STALE_BUFFER_SLOT) { - freeBufferLocked(slot); - } - - mSlots[slot].mFence = Fence::NO_FENCE; - - return err; -} - -bool GonkConsumerBase::stillTracking(int slot, - const sp<GraphicBuffer> graphicBuffer) { - if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { - return false; - } - return (mSlots[slot].mGraphicBuffer != NULL && - mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseLL.h b/widget/gonk/nativewindow/GonkConsumerBaseLL.h deleted file mode 100644 index 0b2c2d166..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseLL.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKCONSUMERBASE_LL_H -#define NATIVEWINDOW_GONKCONSUMERBASE_LL_H - -#include <ui/GraphicBuffer.h> - -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> -#include <gui/IConsumerListener.h> - -#include "GonkBufferQueueLL.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class String8; - -// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It -// handles common tasks like management of the connection to the GonkBufferQueue -// and the buffer pool. -class GonkConsumerBase : public virtual RefBase, - protected ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - virtual ~GonkConsumerBase(); - - // abandon frees all the buffers and puts the GonkConsumerBase into the - // 'abandoned' state. Once put in this state the GonkConsumerBase can never - // leave it. When in the 'abandoned' state, all methods of the - // IGraphicBufferProducer interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the GonkConsumerBase, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client - // or by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the GonkConsumerBase that will be used to identify it in - // log messages. - void setName(const String8& name); - - // dump writes the current state to a string. Child classes should add - // their state to the dump by overriding the dumpLocked method, which is - // called by these methods after locking the mutex. - void dump(String8& result) const; - void dump(String8& result, const char* prefix) const; - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const wp<FrameAvailableListener>& listener); - -private: - GonkConsumerBase(const GonkConsumerBase&); - void operator=(const GonkConsumerBase&); - -protected: - // GonkConsumerBase constructs a new GonkConsumerBase object to consume image - // buffers from the given IGonkGraphicBufferConsumer. - // The controlledByApp flag indicates that this consumer is under the application's - // control. - GonkConsumerBase(const sp<IGonkGraphicBufferConsumer>& consumer, bool controlledByApp = false); - - // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that GonkConsumerBase - // can coordinate the clean-up by calling into virtual methods implemented - // by the derived classes. This would not be possible from the - // ConsuemrBase dtor because by the time that gets called the derived - // classes have already been destructed. - // - // This methods should not need to be overridden by derived classes, but - // if they are overridden the GonkConsumerBase implementation must be called - // from the derived class. - virtual void onLastStrongRef(const void* id); - - // Implementation of the IConsumerListener interface. These - // calls are used to notify the GonkConsumerBase of asynchronous events in the - // GonkBufferQueue. The onFrameAvailable and onBuffersReleased methods should - // not need to be overridden by derived classes, but if they are overridden - // the GonkConsumerBase implementation must be called from the derived class. - // The GonkConsumerBase version of onSidebandStreamChanged does nothing and can - // be overriden by derived classes if they want the notification. -#if ANDROID_VERSION == 21 - virtual void onFrameAvailable(); -#else - virtual void onFrameAvailable(const ::android::BufferItem& item); - virtual void onFrameReplaced(const ::android::BufferItem& item) {}; -#endif - virtual void onBuffersReleased(); - virtual void onSidebandStreamChanged(); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot. Otherwise it has no effect. - // - // Derived classes should override this method to clean up any state they - // keep per slot. If it is overridden, the derived class's implementation - // must call GonkConsumerBase::freeBufferLocked. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex); - - // abandonLocked puts the GonkBufferQueue into the abandoned state, causing - // all future operations on it to fail. This method rather than the public - // abandon method should be overridden by child classes to add abandon- - // time behavior. - // - // Derived classes should override this method to clean up any object - // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call GonkConsumerBase::abandonLocked. - // - // This method must be called with mMutex locked. - virtual void abandonLocked(); - - // dumpLocked dumps the current state of the GonkConsumerBase object to the - // result string. Each line is prefixed with the string pointed to by the - // prefix argument. The buffer argument points to a buffer that may be - // used for intermediate formatting data, and the size of that buffer is - // indicated by the size argument. - // - // Derived classes should override this method to dump their internal - // state. If this method is overridden the derived class's implementation - // should call GonkConsumerBase::dumpLocked. - // - // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix) const; - - // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and - // updates the buffer slot for the buffer returned. - // - // Derived classes should override this method to perform any - // initialization that must take place the first time a buffer is assigned - // to a slot. If it is overridden the derived class's implementation must - // call GonkConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen); - - // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the GonkBufferQueue. - // - // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the GonkBufferQueue. If - // it is overridden the derived class's implementation must call - // GonkConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer); - - // returns true iff the slot still has the graphicBuffer in it. - bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer); - - // addReleaseFence* adds the sync points associated with a fence to the set - // of sync points that must be reached before the buffer in the given slot - // may be used after the slot has been released. This should be called by - // derived classes each time some asynchronous work is kicked off that - // references the buffer. - status_t addReleaseFence(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence); - status_t addReleaseFenceLocked(int slot, - const sp<GraphicBuffer> graphicBuffer, const sp<Fence>& fence); - - // Slot contains the information and object references that - // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. - struct Slot { - // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if - // no Gralloc buffer is in the slot. - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence which will signal when the buffer associated with - // this buffer slot is no longer being used by the consumer and can be - // overwritten. The buffer can be dequeued before the fence signals; - // the producer is responsible for delaying writes until it signals. - sp<Fence> mFence; - - // the frame number of the last acquired frame for this slot - uint64_t mFrameNumber; - }; - - // mSlots stores the buffers that have been allocated by the GonkBufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of GonkBufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume images buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the abandon - // method. A GonkBufferQueue that has been abandoned will return the NO_INIT - // error from all IConsumerBase methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the GonkConsumerBase in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - wp<FrameAvailableListener> mFrameAvailableListener; - - // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object - // if none is supplied - sp<IGonkGraphicBufferConsumer> mConsumer; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkConsumerBase objects. It must be locked whenever the - // member variables are accessed or when any of the *Locked methods are - // called. - // - // This mutex is intended to be locked by derived classes. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKCONSUMERBASE_LL_H diff --git a/widget/gonk/nativewindow/GonkNativeWindow.h b/widget/gonk/nativewindow/GonkNativeWindow.h deleted file mode 100644 index 61b6780b8..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindow.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "GonkNativeWindowLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "GonkNativeWindowKK.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 -# include "GonkNativeWindowJB.h" -#endif diff --git a/widget/gonk/nativewindow/GonkNativeWindowJB.cpp b/widget/gonk/nativewindow/GonkNativeWindowJB.cpp deleted file mode 100644 index e38642009..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowJB.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "GonkNativeWindow" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <utils/Log.h> - -#include "GonkNativeWindowJB.h" -#include "GrallocImages.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/RefPtr.h" - -#define BI_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#define BI_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define BI_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define BI_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define BI_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - -using namespace mozilla; -using namespace mozilla::layers; - -namespace android { - -GonkNativeWindow::GonkNativeWindow(int bufferCount) : - GonkConsumerBase(new GonkBufferQueue(true) ), - mNewFrameCallback(nullptr) -{ - mBufferQueue->setMaxAcquiredBufferCount(bufferCount); -} - -GonkNativeWindow::~GonkNativeWindow() { -} - -void GonkNativeWindow::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mBufferQueue->setConsumerName(name); -} -#if ANDROID_VERSION >= 18 -status_t GonkNativeWindow::acquireBuffer(BufferItem *item, bool waitForFence) { - status_t err; - - if (!item) return BAD_VALUE; - - Mutex::Autolock _l(mMutex); - - err = acquireBufferLocked(item); - if (err != OK) { - if (err != NO_BUFFER_AVAILABLE) { - BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } - return err; - } - - if (waitForFence) { - err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); - if (err != OK) { - BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; - - return OK; -} - -status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, - const sp<Fence>& releaseFence) { - status_t err; - - Mutex::Autolock _l(mMutex); - - err = addReleaseFenceLocked(item.mBuf, releaseFence); - - err = releaseBufferLocked(item.mBuf); - if (err != OK) { - BI_LOGE("Failed to release buffer: %s (%d)", - strerror(-err), err); - } - return err; -} -#endif - -status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferSize(w, h); -} - -status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); -} - -already_AddRefed<TextureClient> -GonkNativeWindow::getCurrentBuffer() { - Mutex::Autolock _l(mMutex); - GonkBufferQueue::BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item); - if (err != NO_ERROR) { - return NULL; - } - - RefPtr<TextureClient> textureClient = - mBufferQueue->getTextureClientFromBuffer(item.mGraphicBuffer.get()); - if (!textureClient) { - return NULL; - } - textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); - return textureClient.forget(); -} - -/* static */ void -GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { - GonkNativeWindow* nativeWindow = - static_cast<GonkNativeWindow*>(closure); - - MOZ_ASSERT(client && !client->IsDead()); - client->ClearRecycleCallback(); - nativeWindow->returnBuffer(client); -} - -void GonkNativeWindow::returnBuffer(TextureClient* client) { - BI_LOGD("GonkNativeWindow::returnBuffer"); - Mutex::Autolock lock(mMutex); - - int index = mBufferQueue->getSlotFromTextureClientLocked(client); - if (index < 0) { - } - - FenceHandle handle = client->GetAndResetReleaseFenceHandle(); - RefPtr<FenceHandle::FdObj> fdObj = handle.GetAndResetFdObj(); - sp<Fence> fence = new Fence(fdObj->GetAndResetFd()); - - addReleaseFenceLocked(index, fence); - - releaseBufferLocked(index); -} - -already_AddRefed<TextureClient> -GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { - Mutex::Autolock lock(mMutex); - return mBufferQueue->getTextureClientFromBuffer(buffer); -} - -void GonkNativeWindow::setNewFrameCallback( - GonkNativeWindowNewFrameCallback* callback) { - BI_LOGD("setNewFrameCallback"); - Mutex::Autolock lock(mMutex); - mNewFrameCallback = callback; -} - -void GonkNativeWindow::onFrameAvailable() { - GonkConsumerBase::onFrameAvailable(); - - if (mNewFrameCallback) { - mNewFrameCallback->OnNewFrame(); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowJB.h b/widget/gonk/nativewindow/GonkNativeWindowJB.h deleted file mode 100644 index e63a7527d..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowJB.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_JB_H -#define NATIVEWINDOW_GONKNATIVEWINDOW_JB_H - -#include <ui/GraphicBuffer.h> -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -#include "GonkConsumerBaseJB.h" -#include "GrallocImages.h" -#include "mozilla/layers/LayersSurfaces.h" - -namespace mozilla { -namespace layers { - class PGrallocBufferChild; -} -} - -namespace android { - -// The user of GonkNativeWindow who wants to receive notification of -// new frames should implement this interface. -class GonkNativeWindowNewFrameCallback { -public: - virtual void OnNewFrame() = 0; -}; - -/** - * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may - * be acquired at once, to be used concurrently by the client. This consumer can - * operate either in synchronous or asynchronous mode. - */ -class GonkNativeWindow: public GonkConsumerBase -{ - typedef mozilla::layers::TextureClient TextureClient; - public: - typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; - - typedef GonkBufferQueue::BufferItem BufferItem; - - enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; - - // Create a new buffer item consumer. The consumerUsage parameter determines - // the consumer usage flags passed to the graphics allocator. The - // bufferCount parameter specifies how many buffers can be locked for user - // access at the same time. - GonkNativeWindow(int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS); - - virtual ~GonkNativeWindow(); - - // set the name of the GonkNativeWindow that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer, filling out the - // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue - // of buffers is empty, and INVALID_OPERATION if the maximum number of - // buffers is already acquired. - // - // Only a fixed number of buffers can be acquired at a time, determined by - // the construction-time bufferCount parameter. If INVALID_OPERATION is - // returned by acquireBuffer, then old buffers must be returned to the - // queue by calling releaseBuffer before more buffers can be acquired. - // - // If waitForFence is true, and the acquired BufferItem has a valid fence object, - // acquireBuffer will wait on the fence with no timeout before returning. -#if ANDROID_VERSION >= 18 - status_t acquireBuffer(BufferItem *item, bool waitForFence = true); -#endif - // Returns an acquired buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be acquired at a time, old buffers - // must be released by calling releaseBuffer to ensure new buffers can be - // acquired by acquireBuffer. Once a BufferItem is released, the caller must - // not access any members of the BufferItem, and should immediately remove - // all of its references to the BufferItem itself. -#if ANDROID_VERSION >= 18 - status_t releaseBuffer(const BufferItem &item, - const sp<Fence>& releaseFence = Fence::NO_FENCE); -#endif - - sp<IGraphicBufferProducer> getProducerInterface() const { return getBufferQueue(); } - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // Get next frame from the queue, caller owns the returned buffer. - already_AddRefed<TextureClient> getCurrentBuffer(); - - // Return the buffer to the queue and mark it as FREE. After that - // the buffer is useable again for the decoder. - void returnBuffer(TextureClient* client); - - already_AddRefed<TextureClient> getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); - - static void RecycleCallback(TextureClient* client, void* closure); - -protected: - virtual void onFrameAvailable(); - -private: - GonkNativeWindowNewFrameCallback* mNewFrameCallback; -}; - -} // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOW_JB_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowKK.cpp b/widget/gonk/nativewindow/GonkNativeWindowKK.cpp deleted file mode 100644 index cf34d6539..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowKK.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "GonkNativeWindow" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <utils/Log.h> - -#include "GonkNativeWindowKK.h" -#include "GrallocImages.h" - -using namespace mozilla; -using namespace mozilla::layers; - -namespace android { - -GonkNativeWindow::GonkNativeWindow(int bufferCount) : - GonkConsumerBase(new GonkBufferQueue(true), false), - mNewFrameCallback(nullptr) -{ - mConsumer->setMaxAcquiredBufferCount(bufferCount); -} - -GonkNativeWindow::GonkNativeWindow(const sp<GonkBufferQueue>& bq, - uint32_t consumerUsage, int bufferCount, bool controlledByApp) : - GonkConsumerBase(bq, controlledByApp) -{ - mConsumer->setConsumerUsageBits(consumerUsage); - mConsumer->setMaxAcquiredBufferCount(bufferCount); -} - -GonkNativeWindow::~GonkNativeWindow() { -} - -void GonkNativeWindow::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GonkNativeWindow::acquireBuffer(BufferItem *item, - nsecs_t presentWhen, bool waitForFence) { - status_t err; - - if (!item) return BAD_VALUE; - - Mutex::Autolock _l(mMutex); - - err = acquireBufferLocked(item, presentWhen); - if (err != OK) { - if (err != NO_BUFFER_AVAILABLE) { - ALOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } - return err; - } - - if (waitForFence) { - err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); - if (err != OK) { - ALOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; - - return OK; -} - -status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, - const sp<Fence>& releaseFence) { - status_t err; - - Mutex::Autolock _l(mMutex); - - err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - - err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer); - if (err != OK) { - ALOGE("Failed to release buffer: %s (%d)", - strerror(-err), err); - } - return err; -} - -status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -already_AddRefed<TextureClient> -GonkNativeWindow::getCurrentBuffer() { - Mutex::Autolock _l(mMutex); - BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item, 0); //??? - if (err != NO_ERROR) { - return NULL; - } - - RefPtr<TextureClient> textureClient = - mConsumer->getTextureClientFromBuffer(item.mGraphicBuffer.get()); - if (!textureClient) { - return NULL; - } - textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); - return textureClient.forget(); -} - -/* static */ void -GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { - GonkNativeWindow* nativeWindow = - static_cast<GonkNativeWindow*>(closure); - - MOZ_ASSERT(client && !client->IsDead()); - client->ClearRecycleCallback(); - nativeWindow->returnBuffer(client); -} - -void GonkNativeWindow::returnBuffer(TextureClient* client) { - ALOGD("GonkNativeWindow::returnBuffer"); - Mutex::Autolock lock(mMutex); - - int index = mConsumer->getSlotFromTextureClientLocked(client); - if (index < 0) { - } - - FenceHandle handle = client->GetAndResetReleaseFenceHandle(); - RefPtr<FenceHandle::FdObj> fdObj = handle.GetAndResetFdObj(); - sp<Fence> fence = new Fence(fdObj->GetAndResetFd()); - - addReleaseFenceLocked(index, - mSlots[index].mGraphicBuffer, - fence); - - releaseBufferLocked(index, mSlots[index].mGraphicBuffer); -} - -already_AddRefed<TextureClient> -GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { - Mutex::Autolock lock(mMutex); - return mConsumer->getTextureClientFromBuffer(buffer); -} - -void GonkNativeWindow::setNewFrameCallback( - GonkNativeWindowNewFrameCallback* callback) { - ALOGD("setNewFrameCallback"); - Mutex::Autolock lock(mMutex); - mNewFrameCallback = callback; -} - -void GonkNativeWindow::onFrameAvailable() { - GonkConsumerBase::onFrameAvailable(); - - if (mNewFrameCallback) { - mNewFrameCallback->OnNewFrame(); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowKK.h b/widget/gonk/nativewindow/GonkNativeWindowKK.h deleted file mode 100644 index e36788b41..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowKK.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_KK_H -#define NATIVEWINDOW_GONKNATIVEWINDOW_KK_H - -#include <ui/GraphicBuffer.h> -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -#include "GonkConsumerBaseKK.h" -#include "GrallocImages.h" -#include "IGonkGraphicBufferConsumer.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/layers/LayersSurfaces.h" - -namespace mozilla { -namespace layers { - class PGrallocBufferChild; -} -} - -namespace android { - -// The user of GonkNativeWindow who wants to receive notification of -// new frames should implement this interface. -class GonkNativeWindowNewFrameCallback { -public: - virtual void OnNewFrame() = 0; -}; - -/** - * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may - * be acquired at once, to be used concurrently by the client. This consumer can - * operate either in synchronous or asynchronous mode. - */ -class GonkNativeWindow: public GonkConsumerBase -{ - typedef mozilla::layers::TextureClient TextureClient; - public: - typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; - typedef IGonkGraphicBufferConsumer::BufferItem BufferItem; - - enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; - - // Create a new buffer item consumer. The consumerUsage parameter determines - // the consumer usage flags passed to the graphics allocator. The - // bufferCount parameter specifies how many buffers can be locked for user - // access at the same time. - // controlledByApp tells whether this consumer is controlled by the - // application. - GonkNativeWindow(int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS); - GonkNativeWindow(const sp<GonkBufferQueue>& bq, uint32_t consumerUsage, - int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS, - bool controlledByApp = false); - - virtual ~GonkNativeWindow(); - - // set the name of the GonkNativeWindow that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer, filling out the - // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue - // of buffers is empty, and INVALID_OPERATION if the maximum number of - // buffers is already acquired. - // - // Only a fixed number of buffers can be acquired at a time, determined by - // the construction-time bufferCount parameter. If INVALID_OPERATION is - // returned by acquireBuffer, then old buffers must be returned to the - // queue by calling releaseBuffer before more buffers can be acquired. - // - // If waitForFence is true, and the acquired BufferItem has a valid fence object, - // acquireBuffer will wait on the fence with no timeout before returning. - status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, - bool waitForFence = true); - - // Returns an acquired buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be acquired at a time, old buffers - // must be released by calling releaseBuffer to ensure new buffers can be - // acquired by acquireBuffer. Once a BufferItem is released, the caller must - // not access any members of the BufferItem, and should immediately remove - // all of its references to the BufferItem itself. - status_t releaseBuffer(const BufferItem &item, - const sp<Fence>& releaseFence = Fence::NO_FENCE); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // Get next frame from the queue, caller owns the returned buffer. - already_AddRefed<TextureClient> getCurrentBuffer(); - - // Return the buffer to the queue and mark it as FREE. After that - // the buffer is useable again for the decoder. - void returnBuffer(TextureClient* client); - - already_AddRefed<TextureClient> getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); - - static void RecycleCallback(TextureClient* client, void* closure); - -protected: - virtual void onFrameAvailable(); - -private: - GonkNativeWindowNewFrameCallback* mNewFrameCallback; -}; - -} // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOW_JB_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowLL.cpp deleted file mode 100644 index 48644a22f..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "GonkNativeWindow" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include <utils/Log.h> - -#include "GonkNativeWindowLL.h" - -using namespace mozilla; -using namespace mozilla::layers; - -namespace android { - -GonkNativeWindow::GonkNativeWindow( - const sp<IGonkGraphicBufferConsumer>& consumer, int bufferCount) : - GonkConsumerBase(consumer, false), - mNewFrameCallback(nullptr) -{ - if (bufferCount != DEFAULT_MAX_BUFFERS) { - status_t err = mConsumer->setMaxAcquiredBufferCount(bufferCount); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set max acquired buffer count to %d", bufferCount); - } -} - -GonkNativeWindow::GonkNativeWindow( - const sp<IGonkGraphicBufferConsumer>& consumer, uint32_t consumerUsage, - int bufferCount, bool controlledByApp) : - GonkConsumerBase(consumer, controlledByApp) -{ - status_t err = mConsumer->setConsumerUsageBits(consumerUsage); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set consumer usage bits to %#x", consumerUsage); - if (bufferCount != DEFAULT_MAX_BUFFERS) { - err = mConsumer->setMaxAcquiredBufferCount(bufferCount); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set max acquired buffer count to %d", bufferCount); - } -} - -GonkNativeWindow::~GonkNativeWindow() { -} - -void GonkNativeWindow::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GonkNativeWindow::acquireBuffer(BufferItem *item, - nsecs_t presentWhen, bool waitForFence) { - status_t err; - - if (!item) return BAD_VALUE; - - Mutex::Autolock _l(mMutex); - - err = acquireBufferLocked(item, presentWhen); - if (err != OK) { - if (err != NO_BUFFER_AVAILABLE) { - ALOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } - return err; - } - - if (waitForFence) { - err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); - if (err != OK) { - ALOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; - - return OK; -} - -status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, - const sp<Fence>& releaseFence) { - status_t err; - - Mutex::Autolock _l(mMutex); - - err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - - err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer); - if (err != OK) { - ALOGE("Failed to release buffer: %s (%d)", - strerror(-err), err); - } - return err; -} - -status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -already_AddRefed<TextureClient> -GonkNativeWindow::getCurrentBuffer() { - Mutex::Autolock _l(mMutex); - BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item, 0); //??? - if (err != NO_ERROR) { - return NULL; - } - - RefPtr<TextureClient> textureClient = - mConsumer->getTextureClientFromBuffer(item.mGraphicBuffer.get()); - if (!textureClient) { - return NULL; - } - textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); - return textureClient.forget(); -} - -/* static */ void -GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { - GonkNativeWindow* nativeWindow = - static_cast<GonkNativeWindow*>(closure); - - MOZ_ASSERT(client && !client->IsDead()); - client->ClearRecycleCallback(); - nativeWindow->returnBuffer(client); -} - -void GonkNativeWindow::returnBuffer(TextureClient* client) { - ALOGD("GonkNativeWindow::returnBuffer"); - Mutex::Autolock lock(mMutex); - - int index = mConsumer->getSlotFromTextureClientLocked(client); - if (index < 0) { - return; - } - - FenceHandle handle = client->GetAndResetReleaseFenceHandle(); - RefPtr<FenceHandle::FdObj> fdObj = handle.GetAndResetFdObj(); - sp<Fence> fence = new Fence(fdObj->GetAndResetFd()); - - status_t err; - err = addReleaseFenceLocked(index, - mSlots[index].mGraphicBuffer, - fence); - - err = releaseBufferLocked(index, mSlots[index].mGraphicBuffer); - - if (err != OK) { - ALOGE("Failed to return buffer: %s (%d)", strerror(-err), err); - } -} - -already_AddRefed<TextureClient> -GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { - Mutex::Autolock lock(mMutex); - return mConsumer->getTextureClientFromBuffer(buffer); -} - -void GonkNativeWindow::setNewFrameCallback( - GonkNativeWindowNewFrameCallback* callback) { - ALOGD("setNewFrameCallback"); - Mutex::Autolock lock(mMutex); - mNewFrameCallback = callback; -} - -#if ANDROID_VERSION == 21 -void GonkNativeWindow::onFrameAvailable() { - GonkConsumerBase::onFrameAvailable(); -#else -void GonkNativeWindow::onFrameAvailable(const ::android::BufferItem &item) { - GonkConsumerBase::onFrameAvailable(item); -#endif - - if (mNewFrameCallback) { - mNewFrameCallback->OnNewFrame(); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.h b/widget/gonk/nativewindow/GonkNativeWindowLL.h deleted file mode 100644 index 64cd6482d..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowLL.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_LL_H -#define NATIVEWINDOW_GONKNATIVEWINDOW_LL_H - -#include <ui/GraphicBuffer.h> - -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -#include "GonkConsumerBaseLL.h" -#include "IGonkGraphicBufferConsumerLL.h" - -namespace android { - -// The user of GonkNativeWindow who wants to receive notification of -// new frames should implement this interface. -class GonkNativeWindowNewFrameCallback { -public: - virtual void OnNewFrame() = 0; -}; - -/** - * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may - * be acquired at once, to be used concurrently by the client. This consumer can - * operate either in synchronous or asynchronous mode. - */ -class GonkNativeWindow: public GonkConsumerBase -{ - typedef mozilla::layers::TextureClient TextureClient; - public: - typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; - typedef GonkBufferQueue::BufferItem BufferItem; - - enum { DEFAULT_MAX_BUFFERS = -1 }; - enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; - - // Create a new buffer item consumer. The consumerUsage parameter determines - // the consumer usage flags passed to the graphics allocator. The - // bufferCount parameter specifies how many buffers can be locked for user - // access at the same time. - // controlledByApp tells whether this consumer is controlled by the - // application. - GonkNativeWindow(const sp<IGonkGraphicBufferConsumer>& consumer, - int bufferCount = DEFAULT_MAX_BUFFERS); - GonkNativeWindow(const sp<IGonkGraphicBufferConsumer>& consumer, - uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, - bool controlledByApp = false); - - virtual ~GonkNativeWindow(); - - // set the name of the GonkNativeWindow that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer, filling out the - // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue - // of buffers is empty, and INVALID_OPERATION if the maximum number of - // buffers is already acquired. - // - // Only a fixed number of buffers can be acquired at a time, determined by - // the construction-time bufferCount parameter. If INVALID_OPERATION is - // returned by acquireBuffer, then old buffers must be returned to the - // queue by calling releaseBuffer before more buffers can be acquired. - // - // If waitForFence is true, and the acquired BufferItem has a valid fence object, - // acquireBuffer will wait on the fence with no timeout before returning. - status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, - bool waitForFence = true); - - // Returns an acquired buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be acquired at a time, old buffers - // must be released by calling releaseBuffer to ensure new buffers can be - // acquired by acquireBuffer. Once a BufferItem is released, the caller must - // not access any members of the BufferItem, and should immediately remove - // all of its references to the BufferItem itself. - status_t releaseBuffer(const BufferItem &item, - const sp<Fence>& releaseFence = Fence::NO_FENCE); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // Get next frame from the queue, caller owns the returned buffer. - already_AddRefed<TextureClient> getCurrentBuffer(); - - // Return the buffer to the queue and mark it as FREE. After that - // the buffer is useable again for the decoder. - void returnBuffer(TextureClient* client); - - already_AddRefed<TextureClient> getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); - - static void RecycleCallback(TextureClient* client, void* closure); - -protected: -#if ANDROID_VERSION == 21 - virtual void onFrameAvailable(); -#else - virtual void onFrameAvailable(const ::android::BufferItem &item); -#endif - -private: - GonkNativeWindowNewFrameCallback* mNewFrameCallback; -}; - -} // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOW_LL_H diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h deleted file mode 100644 index 14541c9b4..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "IGonkGraphicBufferConsumerLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "IGonkGraphicBufferConsumerKK.h" -#endif diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp deleted file mode 100644 index c4c9f6578..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#define EGL_EGLEXT_PROTOTYPES - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> - -#include <binder/Parcel.h> -#include <binder/IInterface.h> - -#include <gui/IConsumerListener.h> -#include "IGonkGraphicBufferConsumerKK.h" - -#include <ui/GraphicBuffer.h> -#include <ui/Fence.h> - -#include <system/window.h> - -namespace android { -// --------------------------------------------------------------------------- - -IGonkGraphicBufferConsumer::BufferItem::BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mBuf) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -status_t IGonkGraphicBufferConsumer::BufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (count < BufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast<uint32_t*>(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mBuf); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t IGonkGraphicBufferConsumer::BufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mBuf); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -enum { - ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - RELEASE_BUFFER, - CONSUMER_CONNECT, - CONSUMER_DISCONNECT, - GET_RELEASED_BUFFERS, - SET_DEFAULT_BUFFER_SIZE, - SET_DEFAULT_MAX_BUFFER_COUNT, - DISABLE_ASYNC_BUFFER, - SET_MAX_ACQUIRED_BUFFER_COUNT, - SET_CONSUMER_NAME, - SET_DEFAULT_BUFFER_FORMAT, - SET_CONSUMER_USAGE_BITS, - SET_TRANSFORM_HINT, - DUMP, -}; - -class BpGonkGraphicBufferConsumer : public BpInterface<IGonkGraphicBufferConsumer> -{ -public: - BpGonkGraphicBufferConsumer(const sp<IBinder>& impl) - : BpInterface<IGonkGraphicBufferConsumer>(impl) - { - } - - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt64(presentWhen); - status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.read(*buffer); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - const sp<Fence>& releaseFence) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(buf); - data.writeInt64(frameNumber); - data.write(*releaseFence); - status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeStrongBinder(consumer->asBinder()); - data.writeInt32(controlledByApp); - status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerDisconnect() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t getReleasedBuffers(uint32_t* slotMask) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); - if (result != NO_ERROR) { - return result; - } - *slotMask = reply.readInt32(); - return reply.readInt32(); - } - - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setDefaultMaxBufferCount(int bufferCount) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(bufferCount); - status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t disableAsyncBuffer() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(maxAcquiredBuffers); - status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual void setConsumerName(const String8& name) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(name); - remote()->transact(SET_CONSUMER_NAME, data, &reply); - } - - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(defaultFormat); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setConsumerUsageBits(uint32_t usage) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(usage); - status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setTransformHint(uint32_t hint) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(hint); - status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual void dumpToString(String8& result, const char* prefix) const { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(result); - data.writeString8(String8(prefix ? prefix : "")); - remote()->transact(DUMP, data, &reply); - reply.readString8(); - } -}; - -IMPLEMENT_META_INTERFACE(GonkGraphicBufferConsumer, "android.gui.IGonkGraphicBufferConsumer"); -// ---------------------------------------------------------------------- - -status_t BnGonkGraphicBufferConsumer::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case ACQUIRE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - BufferItem item; - int64_t presentWhen = data.readInt64(); - status_t result = acquireBuffer(&item, presentWhen); - status_t err = reply->write(item); - if (err) return err; - reply->writeInt32(result); - return NO_ERROR; - } break; - case RELEASE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - int buf = data.readInt32(); - uint64_t frameNumber = data.readInt64(); - sp<Fence> releaseFence = new Fence(); - status_t err = data.read(*releaseFence); - if (err) return err; - status_t result = releaseBuffer(buf, frameNumber, releaseFence); - reply->writeInt32(result); - return NO_ERROR; - } break; - - case CONSUMER_CONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() ); - bool controlledByApp = data.readInt32(); - status_t result = consumerConnect(consumer, controlledByApp); - reply->writeInt32(result); - return NO_ERROR; - } break; - - case CONSUMER_DISCONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = consumerDisconnect(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case GET_RELEASED_BUFFERS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t slotMask; - status_t result = getReleasedBuffers(&slotMask); - reply->writeInt32(slotMask); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_SIZE: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - status_t result = setDefaultBufferSize(w, h); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_MAX_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t bufferCount = data.readInt32(); - status_t result = setDefaultMaxBufferCount(bufferCount); - reply->writeInt32(result); - return NO_ERROR; - } break; - case DISABLE_ASYNC_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = disableAsyncBuffer(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t maxAcquiredBuffers = data.readInt32(); - status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_NAME: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - setConsumerName( data.readString8() ); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_FORMAT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t defaultFormat = data.readInt32(); - status_t result = setDefaultBufferFormat(defaultFormat); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_USAGE_BITS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t usage = data.readInt32(); - status_t result = setConsumerUsageBits(usage); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_TRANSFORM_HINT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t hint = data.readInt32(); - status_t result = setTransformHint(hint); - reply->writeInt32(result); - return NO_ERROR; - } break; - - case DUMP: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - String8 result = data.readString8(); - String8 prefix = data.readString8(); - static_cast<IGonkGraphicBufferConsumer*>(this)->dumpToString(result, prefix); - reply->writeString8(result); - return NO_ERROR; - } - } - return BBinder::onTransact(code, data, reply, flags); -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h deleted file mode 100644 index ce51e1ef2..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_KK_H -#define NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_KK_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> - -#include <binder/IInterface.h> -#include <ui/Rect.h> - -#include "mozilla/Types.h" -#include "mozilla/layers/LayersSurfaces.h" - -namespace mozilla { - -namespace layers { -class TextureClient; -} -} - -namespace android { -// ---------------------------------------------------------------------------- - -class MOZ_EXPORT IConsumerListener; -class MOZ_EXPORT GraphicBuffer; -class MOZ_EXPORT Fence; - -class IGonkGraphicBufferConsumer : public IInterface { - typedef mozilla::layers::TextureClient TextureClient; -public: - - // public facing structure for BufferSlot - class BufferItem : public Flattenable<BufferItem> { - friend class Flattenable<BufferItem>; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - enum { INVALID_BUFFER_SLOT = -1 }; - BufferItem(); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp<Fence> mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer - int mBuf; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; - }; - - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the BufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - // - // If presentWhen is nonzero, it indicates the time when the buffer will - // be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) = 0; - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) = 0; - - // consumerConnect connects a consumer to the BufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // BufferQueue is placed into the "abandoned" state, causing most - // interactions with the BufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumer may not be NULL. - virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0; - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed and the BufferQueue is placed in the "abandoned" - // state, causing most interactions with the BufferQueue by the producer to - // fail. - virtual status_t consumerDisconnect() = 0; - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots have been released by the BufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - virtual status_t getReleasedBuffers(uint32_t* slotMask) = 0; - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - virtual status_t disableAsyncBuffer() = 0; - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the BufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name) = 0; - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - virtual status_t setConsumerUsageBits(uint32_t usage) = 0; - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - virtual status_t setTransformHint(uint32_t hint) = 0; - - // dump state into a string - virtual void dumpToString(String8& result, const char* prefix) const = 0; - -public: - DECLARE_META_INTERFACE(GonkGraphicBufferConsumer); -}; - -// ---------------------------------------------------------------------------- - -class BnGonkGraphicBufferConsumer : public BnInterface<IGonkGraphicBufferConsumer> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp deleted file mode 100644 index 729ed6736..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp +++ /dev/null @@ -1,565 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/NativeHandle.h> - -#include <binder/Parcel.h> -#include <binder/IInterface.h> - -#include <gui/IConsumerListener.h> -#include "IGonkGraphicBufferConsumerLL.h" - -#include <ui/GraphicBuffer.h> -#include <ui/Fence.h> - -#include <system/window.h> - -#include "mozilla/layers/TextureClient.h" - -namespace android { -// --------------------------------------------------------------------------- - -IGonkGraphicBufferConsumer::BufferItem::BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mBuf) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -static void writeBoolAsInt(void*& buffer, size_t& size, bool b) { - FlattenableUtils::write(buffer, size, static_cast<int32_t>(b)); -} - -static bool readBoolFromInt(void const*& buffer, size_t& size) { - int32_t i; - FlattenableUtils::read(buffer, size, i); - return static_cast<bool>(i); -} - -status_t IGonkGraphicBufferConsumer::BufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (size < BufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast<uint32_t*>(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - writeBoolAsInt(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mBuf); - writeBoolAsInt(buffer, size, mIsDroppable); - writeBoolAsInt(buffer, size, mAcquireCalled); - writeBoolAsInt(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t IGonkGraphicBufferConsumer::BufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - mIsAutoTimestamp = readBoolFromInt(buffer, size); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mBuf); - mIsDroppable = readBoolFromInt(buffer, size); - mAcquireCalled = readBoolFromInt(buffer, size); - mTransformToDisplayInverse = readBoolFromInt(buffer, size); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -enum { - ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - DETACH_BUFFER, - ATTACH_BUFFER, - RELEASE_BUFFER, - CONSUMER_CONNECT, - CONSUMER_DISCONNECT, - GET_RELEASED_BUFFERS, - SET_DEFAULT_BUFFER_SIZE, - SET_DEFAULT_MAX_BUFFER_COUNT, - DISABLE_ASYNC_BUFFER, - SET_MAX_ACQUIRED_BUFFER_COUNT, - SET_CONSUMER_NAME, - SET_DEFAULT_BUFFER_FORMAT, - SET_CONSUMER_USAGE_BITS, - SET_TRANSFORM_HINT, - GET_SIDEBAND_STREAM, - DUMP, -}; - - -class BpGonkGraphicBufferConsumer : public BpInterface<IGonkGraphicBufferConsumer> -{ -public: - BpGonkGraphicBufferConsumer(const sp<IBinder>& impl) - : BpInterface<IGonkGraphicBufferConsumer>(impl) - { - } - - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt64(presentWhen); - status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.read(*buffer); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t detachBuffer(int slot) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(slot); - status_t result = remote()->transact(DETACH_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.readInt32(); - return result; - } - - virtual status_t attachBuffer(int* slot, const sp<GraphicBuffer>& buffer) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.write(*buffer.get()); - status_t result = remote()->transact(ATTACH_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - *slot = reply.readInt32(); - result = reply.readInt32(); - return result; - } - - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(buf); - data.writeInt64(frameNumber); - data.write(*releaseFence); - status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeStrongBinder(consumer->asBinder()); - data.writeInt32(controlledByApp); - status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerDisconnect() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t getReleasedBuffers(uint64_t* slotMask) { - Parcel data, reply; - if (slotMask == NULL) { - ALOGE("getReleasedBuffers: slotMask must not be NULL"); - return BAD_VALUE; - } - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); - if (result != NO_ERROR) { - return result; - } - *slotMask = reply.readInt64(); - return reply.readInt32(); - } - - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setDefaultMaxBufferCount(int bufferCount) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(bufferCount); - status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t disableAsyncBuffer() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(maxAcquiredBuffers); - status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual void setConsumerName(const String8& name) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(name); - remote()->transact(SET_CONSUMER_NAME, data, &reply); - } - - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(defaultFormat); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setConsumerUsageBits(uint32_t usage) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(usage); - status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setTransformHint(uint32_t hint) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(hint); - status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual sp<NativeHandle> getSidebandStream() const { - Parcel data, reply; - status_t err; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) { - return NULL; - } - sp<NativeHandle> stream; - if (reply.readInt32()) { - stream = NativeHandle::create(reply.readNativeHandle(), true); - } - return stream; - } - - virtual void dumpToString(String8& result, const char* prefix) const { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(result); - data.writeString8(String8(prefix ? prefix : "")); - remote()->transact(DUMP, data, &reply); - reply.readString8(); - } - - // Added by mozilla - virtual already_AddRefed<mozilla::layers::TextureClient> - getTextureClientFromBuffer(ANativeWindowBuffer* buffer) - { - return nullptr; - } - - virtual int - getSlotFromTextureClientLocked(mozilla::layers::TextureClient* client) const - { - return BAD_VALUE; - } -}; - -IMPLEMENT_META_INTERFACE(GonkGraphicBufferConsumer, "android.gui.IGonkGraphicBufferConsumer"); - -// ---------------------------------------------------------------------- - -status_t BnGonkGraphicBufferConsumer::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case ACQUIRE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - BufferItem item; - int64_t presentWhen = data.readInt64(); - status_t result = acquireBuffer(&item, presentWhen); - status_t err = reply->write(item); - if (err) return err; - reply->writeInt32(result); - return NO_ERROR; - } break; - case DETACH_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - int slot = data.readInt32(); - int result = detachBuffer(slot); - reply->writeInt32(result); - return NO_ERROR; - } break; - case ATTACH_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - sp<GraphicBuffer> buffer = new GraphicBuffer(); - data.read(*buffer.get()); - int slot; - int result = attachBuffer(&slot, buffer); - reply->writeInt32(slot); - reply->writeInt32(result); - return NO_ERROR; - } break; - case RELEASE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - int buf = data.readInt32(); - uint64_t frameNumber = data.readInt64(); - sp<Fence> releaseFence = new Fence(); - status_t err = data.read(*releaseFence); - if (err) return err; - status_t result = releaseBuffer(buf, frameNumber, releaseFence); - reply->writeInt32(result); - return NO_ERROR; - } break; - case CONSUMER_CONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - sp<IConsumerListener> consumer = IConsumerListener::asInterface( data.readStrongBinder() ); - bool controlledByApp = data.readInt32(); - status_t result = consumerConnect(consumer, controlledByApp); - reply->writeInt32(result); - return NO_ERROR; - } break; - case CONSUMER_DISCONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = consumerDisconnect(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case GET_RELEASED_BUFFERS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint64_t slotMask; - status_t result = getReleasedBuffers(&slotMask); - reply->writeInt64(slotMask); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_SIZE: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - status_t result = setDefaultBufferSize(w, h); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_MAX_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t bufferCount = data.readInt32(); - status_t result = setDefaultMaxBufferCount(bufferCount); - reply->writeInt32(result); - return NO_ERROR; - } break; - case DISABLE_ASYNC_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = disableAsyncBuffer(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t maxAcquiredBuffers = data.readInt32(); - status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_NAME: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - setConsumerName( data.readString8() ); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_FORMAT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t defaultFormat = data.readInt32(); - status_t result = setDefaultBufferFormat(defaultFormat); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_USAGE_BITS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t usage = data.readInt32(); - status_t result = setConsumerUsageBits(usage); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_TRANSFORM_HINT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t hint = data.readInt32(); - status_t result = setTransformHint(hint); - reply->writeInt32(result); - return NO_ERROR; - } break; - case DUMP: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - String8 result = data.readString8(); - String8 prefix = data.readString8(); - static_cast<IGonkGraphicBufferConsumer*>(this)->dumpToString(result, prefix); - reply->writeString8(result); - return NO_ERROR; - } - } - return BBinder::onTransact(code, data, reply, flags); -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h deleted file mode 100644 index 8a93a0849..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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. - */ - -#ifndef NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_LL_H -#define NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_LL_H - -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/RefBase.h> -#include <utils/Timers.h> - -#include <binder/IInterface.h> -#include <ui/Rect.h> - -#include "mozilla/RefPtr.h" - -class ANativeWindowBuffer; - -namespace mozilla { -namespace layers { -class TextureClient; -} -} - -namespace android { -// ---------------------------------------------------------------------------- - -class Fence; -class GraphicBuffer; -class IConsumerListener; -class NativeHandle; - -class IGonkGraphicBufferConsumer : public IInterface { -public: - - // public facing structure for BufferSlot - class BufferItem : public Flattenable<BufferItem> { - friend class Flattenable<BufferItem>; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - // The default value of mBuf, used to indicate this doesn't correspond to a slot. - enum { INVALID_BUFFER_SLOT = -1 }; - BufferItem(); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp<GraphicBuffer> mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp<Fence> mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // refer to NATIVE_WINDOW_TRANSFORM_* in <window.h> - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // refer to NATIVE_WINDOW_SCALING_* in <window.h> - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. This value - // is guaranteed to be monotonically increasing for each newly - // acquired buffer. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mBuf; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; - }; - - enum { - // Returned by releaseBuffer, after which the consumer must - // free any references to the just-released buffer that it might have. - STALE_BUFFER_SLOT = 1, - // Returned by dequeueBuffer if there are no pending buffers available. - NO_BUFFER_AVAILABLE, - // Returned by dequeueBuffer if it's too early for the buffer to be acquired. - PRESENT_LATER, - }; - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the BufferQueue. If no buffer is pending then it returns - // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the - // information about the buffer is returned in BufferItem. - // - // If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - // - // If presentWhen is non-zero, it indicates the time when the buffer will - // be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - // - // Return of NO_ERROR means the operation completed as normal. - // - // Return of a positive value means the operation could not be completed - // at this time, but the user should try again later: - // * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer) - // * PRESENT_LATER - the buffer's timestamp is farther in the future - // - // Return of a negative value means an error has occurred: - // * INVALID_OPERATION - too many buffers have been acquired - virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0; - - // detachBuffer attempts to remove all ownership of the buffer in the given - // slot from the buffer queue. If this call succeeds, the slot will be - // freed, and there will be no way to obtain the buffer from this interface. - // The freed slot will remain unallocated until either it is selected to - // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached - // to the slot. The buffer must have already been acquired. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - the given slot number is invalid, either because it is - // out of the range [0, NUM_BUFFER_SLOTS) or because the slot - // it refers to is not currently acquired. - virtual status_t detachBuffer(int slot) = 0; - - // attachBuffer attempts to transfer ownership of a buffer to the buffer - // queue. If this call succeeds, it will be as if this buffer was acquired - // from the returned slot number. As such, this call will fail if attaching - // this buffer would cause too many buffers to be simultaneously acquired. - // - // If the buffer is successfully attached, its frameNumber is initialized - // to 0. This must be passed into the releaseBuffer call or else the buffer - // will be deallocated as stale. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - outSlot or buffer were NULL - // * INVALID_OPERATION - cannot attach the buffer because it would cause too - // many buffers to be acquired. - // * NO_MEMORY - no free slots available - virtual status_t attachBuffer(int *outSlot, - const sp<GraphicBuffer>& buffer) = 0; - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - // - // Return of NO_ERROR means the operation completed as normal. - // - // Return of a positive value means the operation could not be completed - // at this time, but the user should try again later: - // * STALE_BUFFER_SLOT - see above (second paragraph) - // - // Return of a negative value means an error has occurred: - // * BAD_VALUE - one of the following could've happened: - // * the buffer slot was invalid - // * the fence was NULL - // * the buffer slot specified is not in the acquired state - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& releaseFence) = 0; - - // consumerConnect connects a consumer to the BufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // BufferQueue is placed into the "abandoned" state, causing most - // interactions with the BufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumer may not be NULL. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned - // * BAD_VALUE - a NULL consumer was provided - virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp) = 0; - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed and the BufferQueue is placed in the "abandoned" - // state, causing most interactions with the BufferQueue by the producer to - // fail. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - no consumer is currently connected - virtual status_t consumerDisconnect() = 0; - - // getReleasedBuffers sets the value pointed to by slotMask to a bit set. - // Each bit index with a 1 corresponds to a released buffer slot with that - // index value. In particular, a released buffer is one that has - // been released by the BufferQueue but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. - virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0; - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - either w or h was zero - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - bufferCount was out of range (see above). - virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - // - // Return of a value other than NO_ERROR means an error has occurred: - // * INVALID_OPERATION - attempting to call this after consumerConnect. - virtual status_t disableAsyncBuffer() = 0; - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the BufferQueue. - // - // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - maxAcquiredBuffers was out of range (see above). - // * INVALID_OPERATION - attempting to call this after a producer connected. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name) = 0; - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setConsumerUsageBits(uint32_t usage) = 0; - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setTransformHint(uint32_t hint) = 0; - - // Retrieve the sideband buffer stream, if any. - virtual sp<NativeHandle> getSidebandStream() const = 0; - - // dump state into a string - virtual void dumpToString(String8& result, const char* prefix) const = 0; - - // Added by mozilla - virtual already_AddRefed<mozilla::layers::TextureClient> - getTextureClientFromBuffer(ANativeWindowBuffer* buffer) = 0; - - virtual int getSlotFromTextureClientLocked(mozilla::layers::TextureClient* client) const = 0; - -public: - DECLARE_META_INTERFACE(GonkGraphicBufferConsumer); -}; - -// ---------------------------------------------------------------------------- - -class BnGonkGraphicBufferConsumer : public BnInterface<IGonkGraphicBufferConsumer> -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build deleted file mode 100644 index fbcee601c..000000000 --- a/widget/gonk/nativewindow/moz.build +++ /dev/null @@ -1,104 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -EXPORTS += [ - 'GonkBufferQueue.h', - 'GonkNativeWindow.h', -] - -if CONFIG['ANDROID_VERSION'] >= '19': - EXPORTS += [ - 'IGonkGraphicBufferConsumer.h', - ] - -if CONFIG['ANDROID_VERSION'] >= '21': - EXPORTS += [ - 'GonkBufferQueueLL/GonkBufferQueueDefs.h', - 'GonkBufferQueueLL/GonkBufferQueueLL.h', - 'GonkBufferQueueLL/GonkBufferQueueProducer.h', - 'GonkBufferQueueLL/GonkBufferSlot.h', - 'GonkConsumerBaseLL.h', - 'GonkNativeWindowLL.h', - 'IGonkGraphicBufferConsumerLL.h', - ] -elif CONFIG['ANDROID_VERSION'] >= '19': - EXPORTS += [ - 'GonkBufferQueueKK.h', - 'GonkConsumerBaseKK.h', - 'GonkNativeWindowKK.h', - 'IGonkGraphicBufferConsumerKK.h', - ] -elif CONFIG['ANDROID_VERSION'] in ('17', '18'): - EXPORTS += [ - 'GonkBufferQueueJB.h', - 'GonkConsumerBaseJB.h', - 'GonkNativeWindowJB.h', - ] - -if CONFIG['MOZ_WEBRTC']: - if CONFIG['ANDROID_VERSION'] >= '21': - SOURCES += [ - 'GonkBufferQueueLL/GonkBufferItem.cpp', - 'GonkBufferQueueLL/GonkBufferQueueConsumer.cpp', - 'GonkBufferQueueLL/GonkBufferQueueCore.cpp', - 'GonkBufferQueueLL/GonkBufferQueueLL.cpp', - 'GonkBufferQueueLL/GonkBufferQueueProducer.cpp', - 'GonkBufferQueueLL/GonkBufferSlot.cpp', - 'GonkConsumerBaseLL.cpp', - 'GonkNativeWindowLL.cpp', - 'IGonkGraphicBufferConsumerLL.cpp', - ] - elif CONFIG['ANDROID_VERSION'] >= '19': - SOURCES += [ - 'GonkBufferQueueKK.cpp', - 'GonkConsumerBaseKK.cpp', - 'GonkNativeWindowKK.cpp', - 'IGonkGraphicBufferConsumerKK.cpp', - ] - elif CONFIG['ANDROID_VERSION'] in ('17', '18'): - SOURCES += [ - 'GonkBufferQueueJB.cpp', - 'GonkConsumerBaseJB.cpp', - 'GonkNativeWindowJB.cpp', - ] - -if CONFIG['ANDROID_VERSION'] >= '18': - SOURCES += [ - 'FakeSurfaceComposer.cpp', - ] - -include('/ipc/chromium/chromium-config.mozbuild') - -if CONFIG['ANDROID_VERSION'] >= '18': - LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include', - ] - ] - -DEFINES['HAVE_ANDROID_OS'] = True - -# Suppress some GCC warnings being treated as errors: -# - about attributes on forward declarations for types that are already -# defined, which complains about an important MOZ_EXPORT for android::AString -if CONFIG['GNU_CC']: - CXXFLAGS += ['-Wno-error=attributes', '-Wno-overloaded-virtual'] - -FINAL_LIBRARY = 'xul' - -DISABLE_STL_WRAPPING = True - -NO_VISIBILITY_FLAGS = True diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp deleted file mode 100644 index 24e791b4b..000000000 --- a/widget/gonk/nsAppShell.cpp +++ /dev/null @@ -1,1087 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set ts=4 sw=4 sts=4 tw=80 et: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <hardware_legacy/power.h> -#include <signal.h> -#include <sys/epoll.h> -#include <sys/ioctl.h> -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> -#include <utils/BitSet.h> - -#include "base/basictypes.h" -#include "GonkPermission.h" -#include "libdisplay/BootAnimation.h" -#include "nscore.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Hal.h" -#include "mozilla/MouseEvents.h" -#include "mozilla/Mutex.h" -#include "mozilla/Services.h" -#include "mozilla/TextEvents.h" -#if ANDROID_VERSION >= 18 -#include "nativewindow/FakeSurfaceComposer.h" -#endif -#include "nsAppShell.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/dom/Touch.h" -#include "nsGkAtoms.h" -#include "nsIObserverService.h" -#include "nsIScreen.h" -#include "nsScreenManagerGonk.h" -#include "nsThreadUtils.h" -#include "nsWindow.h" -#include "OrientationObserver.h" -#include "GonkMemoryPressureMonitoring.h" - -#include "android/log.h" -#include "libui/EventHub.h" -#include "libui/InputReader.h" -#include "libui/InputDispatcher.h" - -#include "mozilla/Preferences.h" -#include "GeckoProfiler.h" - -// Defines kKeyMapping and GetKeyNameIndex() -#include "GonkKeyMapping.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "GeckoTouchDispatcher.h" - -#undef LOG -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#ifdef VERBOSE_LOG_ENABLED -# define VERBOSE_LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#else -# define VERBOSE_LOG(args...) \ - (void)0 -#endif - -using namespace android; -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::services; -using namespace mozilla::widget; - -bool gDrawRequest = false; -static nsAppShell *gAppShell = nullptr; -static int epollfd = 0; -static int signalfds[2] = {0}; -static bool sDevInputAudioJack; -static int32_t sHeadphoneState; -static int32_t sMicrophoneState; - -// Amount of time in MS before an input is considered expired. -static const uint64_t kInputExpirationThresholdMs = 1000; -static const char kKey_WAKE_LOCK_ID[] = "GeckoKeyEvent"; - -NS_IMPL_ISUPPORTS_INHERITED(nsAppShell, nsBaseAppShell, nsIObserver) - -static uint64_t -nanosecsToMillisecs(nsecs_t nsecs) -{ - return nsecs / 1000000; -} - -namespace mozilla { - -bool ProcessNextEvent() -{ - return gAppShell->ProcessNextNativeEvent(true); -} - -void NotifyEvent() -{ - gAppShell->NotifyNativeEvent(); -} - -} // namespace mozilla - -static void -pipeHandler(int fd, FdHandler *data) -{ - ssize_t len; - do { - char tmp[32]; - len = read(fd, tmp, sizeof(tmp)); - } while (len > 0); -} - -struct Touch { - int32_t id; - PointerCoords coords; -}; - -struct UserInputData { - uint64_t timeMs; - enum { - MOTION_DATA, - KEY_DATA - } type; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t deviceId; - union { - struct { - int32_t keyCode; - int32_t scanCode; - } key; - struct { - int32_t touchCount; - ::Touch touches[MAX_POINTERS]; - } motion; - }; -}; - -static mozilla::Modifiers -getDOMModifiers(int32_t metaState) -{ - mozilla::Modifiers result = 0; - if (metaState & (AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { - result |= MODIFIER_ALT; - } - if (metaState & (AMETA_SHIFT_ON | - AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { - result |= MODIFIER_SHIFT; - } - if (metaState & AMETA_FUNCTION_ON) { - result |= MODIFIER_FN; - } - if (metaState & (AMETA_CTRL_ON | - AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { - result |= MODIFIER_CONTROL; - } - if (metaState & (AMETA_META_ON | - AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { - result |= MODIFIER_META; - } - if (metaState & AMETA_CAPS_LOCK_ON) { - result |= MODIFIER_CAPSLOCK; - } - if (metaState & AMETA_NUM_LOCK_ON) { - result |= MODIFIER_NUMLOCK; - } - if (metaState & AMETA_SCROLL_LOCK_ON) { - result |= MODIFIER_SCROLLLOCK; - } - return result; -} - -class MOZ_STACK_CLASS KeyEventDispatcher -{ -public: - KeyEventDispatcher(const UserInputData& aData, - KeyCharacterMap* aKeyCharMap); - void Dispatch(); - -private: - const UserInputData& mData; - sp<KeyCharacterMap> mKeyCharMap; - - char16_t mChar; - char16_t mUnmodifiedChar; - - uint32_t mDOMKeyCode; - uint32_t mDOMKeyLocation; - KeyNameIndex mDOMKeyNameIndex; - CodeNameIndex mDOMCodeNameIndex; - char16_t mDOMPrintableKeyValue; - - bool IsKeyPress() const - { - return mData.action == AKEY_EVENT_ACTION_DOWN; - } - bool IsRepeat() const - { - return IsKeyPress() && (mData.flags & AKEY_EVENT_FLAG_LONG_PRESS); - } - - char16_t PrintableKeyValue() const; - - int32_t UnmodifiedMetaState() const - { - return mData.metaState & - ~(AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON | - AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON | - AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); - } - - static bool IsControlChar(char16_t aChar) - { - return (aChar < ' ' || aChar == 0x7F); - } - - void DispatchKeyDownEvent(); - void DispatchKeyUpEvent(); - nsEventStatus DispatchKeyEventInternal(EventMessage aEventMessage); -}; - -KeyEventDispatcher::KeyEventDispatcher(const UserInputData& aData, - KeyCharacterMap* aKeyCharMap) - : mData(aData) - , mKeyCharMap(aKeyCharMap) - , mChar(0) - , mUnmodifiedChar(0) - , mDOMPrintableKeyValue(0) -{ - // XXX Printable key's keyCode value should be computed with actual - // input character. - mDOMKeyCode = (mData.key.keyCode < (ssize_t)ArrayLength(kKeyMapping)) ? - kKeyMapping[mData.key.keyCode] : 0; - mDOMKeyNameIndex = GetKeyNameIndex(mData.key.keyCode); - mDOMCodeNameIndex = GetCodeNameIndex(mData.key.scanCode); - mDOMKeyLocation = - WidgetKeyboardEvent::ComputeLocationFromCodeValue(mDOMCodeNameIndex); - - if (!mKeyCharMap.get()) { - return; - } - - mChar = mKeyCharMap->getCharacter(mData.key.keyCode, mData.metaState); - if (IsControlChar(mChar)) { - mChar = 0; - } - int32_t unmodifiedMetaState = UnmodifiedMetaState(); - if (mData.metaState == unmodifiedMetaState) { - mUnmodifiedChar = mChar; - } else { - mUnmodifiedChar = mKeyCharMap->getCharacter(mData.key.keyCode, - unmodifiedMetaState); - if (IsControlChar(mUnmodifiedChar)) { - mUnmodifiedChar = 0; - } - } - - mDOMPrintableKeyValue = PrintableKeyValue(); -} - -char16_t -KeyEventDispatcher::PrintableKeyValue() const -{ - if (mDOMKeyNameIndex != KEY_NAME_INDEX_USE_STRING) { - return 0; - } - return mChar ? mChar : mUnmodifiedChar; -} - -nsEventStatus -KeyEventDispatcher::DispatchKeyEventInternal(EventMessage aEventMessage) -{ - WidgetKeyboardEvent event(true, aEventMessage, nullptr); - if (aEventMessage == eKeyPress) { - // XXX If the charCode is not a printable character, the charCode - // should be computed without Ctrl/Alt/Meta modifiers. - event.mCharCode = static_cast<uint32_t>(mChar); - } - if (!event.mCharCode) { - event.mKeyCode = mDOMKeyCode; - } - event.mIsChar = !!event.mCharCode; - event.mIsRepeat = IsRepeat(); - event.mKeyNameIndex = mDOMKeyNameIndex; - if (mDOMPrintableKeyValue) { - event.mKeyValue = mDOMPrintableKeyValue; - } - event.mCodeNameIndex = mDOMCodeNameIndex; - event.mModifiers = getDOMModifiers(mData.metaState); - event.mLocation = mDOMKeyLocation; - event.mTime = mData.timeMs; - return nsWindow::DispatchKeyInput(event); -} - -void -KeyEventDispatcher::Dispatch() -{ - // XXX Even if unknown key is pressed, DOM key event should be - // dispatched since Gecko for the other platforms are implemented - // as so. - if (!mDOMKeyCode && mDOMKeyNameIndex == KEY_NAME_INDEX_Unidentified) { - VERBOSE_LOG("Got unknown key event code. " - "type 0x%04x code 0x%04x value %d", - mData.action, mData.key.keyCode, IsKeyPress()); - return; - } - - if (IsKeyPress()) { - DispatchKeyDownEvent(); - } else { - DispatchKeyUpEvent(); - } -} - -void -KeyEventDispatcher::DispatchKeyDownEvent() -{ - nsEventStatus status = DispatchKeyEventInternal(eKeyDown); - if (status != nsEventStatus_eConsumeNoDefault) { - DispatchKeyEventInternal(eKeyPress); - } -} - -void -KeyEventDispatcher::DispatchKeyUpEvent() -{ - DispatchKeyEventInternal(eKeyUp); -} - -class SwitchEventRunnable : public mozilla::Runnable { -public: - SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent) - {} - - NS_IMETHOD Run() override - { - hal::NotifySwitchStateFromInputDevice(mEvent.device(), - mEvent.status()); - return NS_OK; - } -private: - hal::SwitchEvent mEvent; -}; - -static void -updateHeadphoneSwitch() -{ - hal::SwitchEvent event; - - switch (sHeadphoneState) { - case AKEY_STATE_UP: - event.status() = hal::SWITCH_STATE_OFF; - break; - case AKEY_STATE_DOWN: - event.status() = sMicrophoneState == AKEY_STATE_DOWN ? - hal::SWITCH_STATE_HEADSET : hal::SWITCH_STATE_HEADPHONE; - break; - default: - return; - } - - event.device() = hal::SWITCH_HEADPHONES; - NS_DispatchToMainThread(new SwitchEventRunnable(event)); -} - -class GeckoPointerController : public PointerControllerInterface { - float mX; - float mY; - int32_t mButtonState; - InputReaderConfiguration* mConfig; -public: - GeckoPointerController(InputReaderConfiguration* config) - : mX(0) - , mY(0) - , mButtonState(0) - , mConfig(config) - {} - - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; - virtual void move(float deltaX, float deltaY); - virtual void setButtonState(int32_t buttonState); - virtual int32_t getButtonState() const; - virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; - virtual void fade(Transition transition) {} - virtual void unfade(Transition transition) {} - virtual void setPresentation(Presentation presentation) {} - virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits) {} - virtual void clearSpots() {} -}; - -bool -GeckoPointerController::getBounds(float* outMinX, - float* outMinY, - float* outMaxX, - float* outMaxY) const -{ - DisplayViewport viewport; - - mConfig->getDisplayInfo(false, &viewport); - - *outMinX = *outMinY = 0; - *outMaxX = viewport.logicalRight; - *outMaxY = viewport.logicalBottom; - return true; -} - -void -GeckoPointerController::move(float deltaX, float deltaY) -{ - float minX, minY, maxX, maxY; - getBounds(&minX, &minY, &maxX, &maxY); - - mX = clamped(mX + deltaX, minX, maxX); - mY = clamped(mY + deltaY, minY, maxY); -} - -void -GeckoPointerController::setButtonState(int32_t buttonState) -{ - mButtonState = buttonState; -} - -int32_t -GeckoPointerController::getButtonState() const -{ - return mButtonState; -} - -void -GeckoPointerController::setPosition(float x, float y) -{ - mX = x; - mY = y; -} - -void -GeckoPointerController::getPosition(float* outX, float* outY) const -{ - *outX = mX; - *outY = mY; -} - -class GeckoInputReaderPolicy : public InputReaderPolicyInterface { - InputReaderConfiguration mConfig; -public: - GeckoInputReaderPolicy() {} - - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); - virtual sp<PointerControllerInterface> obtainPointerController(int32_t -deviceId) - { - return new GeckoPointerController(&mConfig); - }; - virtual void notifyInputDevicesChanged(const android::Vector<InputDeviceInfo>& inputDevices) {}; - virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) - { - return nullptr; - }; - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) - { - return String8::empty(); - }; - - void setDisplayInfo(); - -protected: - virtual ~GeckoInputReaderPolicy() {} -}; - -class GeckoInputDispatcher : public InputDispatcherInterface { -public: - GeckoInputDispatcher(sp<EventHub> &aEventHub) - : mQueueLock("GeckoInputDispatcher::mQueueMutex") - , mEventHub(aEventHub) - , mKeyDownCount(0) - , mKeyEventsFiltered(false) - , mPowerWakelock(false) - { - mTouchDispatcher = GeckoTouchDispatcher::GetInstance(); - } - - virtual void dump(String8& dump); - - virtual void monitor() {} - - // Called on the main thread - virtual void dispatchOnce(); - - // notify* methods are called on the InputReaderThread - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags); - - virtual void setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles); - virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle); - - virtual void setInputDispatchMode(bool enabled, bool frozen); - virtual void setInputFilterEnabled(bool enabled) {} - virtual bool transferTouchFocus(const sp<InputChannel>& fromChannel, - const sp<InputChannel>& toChannel) { return true; } - - virtual status_t registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor); - virtual status_t unregisterInputChannel(const sp<InputChannel>& inputChannel); - - - -protected: - virtual ~GeckoInputDispatcher() { } - -private: - // mQueueLock should generally be locked while using mEventQueue. - // UserInputData is pushed on on the InputReaderThread and - // popped and dispatched on the main thread. - mozilla::Mutex mQueueLock; - std::queue<UserInputData> mEventQueue; - sp<EventHub> mEventHub; - RefPtr<GeckoTouchDispatcher> mTouchDispatcher; - - int mKeyDownCount; - bool mKeyEventsFiltered; - bool mPowerWakelock; -}; - -// GeckoInputReaderPolicy -void -GeckoInputReaderPolicy::setDisplayInfo() -{ - static_assert(static_cast<int>(nsIScreen::ROTATION_0_DEG) == - static_cast<int>(DISPLAY_ORIENTATION_0), - "Orientation enums not matched!"); - static_assert(static_cast<int>(nsIScreen::ROTATION_90_DEG) == - static_cast<int>(DISPLAY_ORIENTATION_90), - "Orientation enums not matched!"); - static_assert(static_cast<int>(nsIScreen::ROTATION_180_DEG) == - static_cast<int>(DISPLAY_ORIENTATION_180), - "Orientation enums not matched!"); - static_assert(static_cast<int>(nsIScreen::ROTATION_270_DEG) == - static_cast<int>(DISPLAY_ORIENTATION_270), - "Orientation enums not matched!"); - - RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); - - uint32_t rotation = nsIScreen::ROTATION_0_DEG; - DebugOnly<nsresult> rv = screen->GetRotation(&rotation); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - LayoutDeviceIntRect screenBounds = screen->GetNaturalBounds(); - - DisplayViewport viewport; - viewport.displayId = 0; - viewport.orientation = rotation; - viewport.physicalRight = viewport.deviceWidth = screenBounds.width; - viewport.physicalBottom = viewport.deviceHeight = screenBounds.height; - if (viewport.orientation == DISPLAY_ORIENTATION_90 || - viewport.orientation == DISPLAY_ORIENTATION_270) { - viewport.logicalRight = screenBounds.height; - viewport.logicalBottom = screenBounds.width; - } else { - viewport.logicalRight = screenBounds.width; - viewport.logicalBottom = screenBounds.height; - } - mConfig.setDisplayInfo(false, viewport); -} - -void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) -{ - *outConfig = mConfig; -} - - -// GeckoInputDispatcher -void -GeckoInputDispatcher::dump(String8& dump) -{ -} - -static bool -isExpired(const UserInputData& data) -{ - uint64_t timeNowMs = - nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC)); - return (timeNowMs - data.timeMs) > kInputExpirationThresholdMs; -} - -void -GeckoInputDispatcher::dispatchOnce() -{ - UserInputData data; - { - MutexAutoLock lock(mQueueLock); - if (mEventQueue.empty()) - return; - data = mEventQueue.front(); - mEventQueue.pop(); - if (!mEventQueue.empty()) - gAppShell->NotifyNativeEvent(); - } - - switch (data.type) { - case UserInputData::MOTION_DATA: { - MOZ_ASSERT_UNREACHABLE("Should not dispatch touch events here anymore"); - break; - } - case UserInputData::KEY_DATA: { - if (!mKeyDownCount) { - // No pending events, the filter state can be updated. - mKeyEventsFiltered = isExpired(data); - } - - mKeyDownCount += (data.action == AKEY_EVENT_ACTION_DOWN) ? 1 : -1; - if (mKeyEventsFiltered) { - return; - } - - sp<KeyCharacterMap> kcm = mEventHub->getKeyCharacterMap(data.deviceId); - KeyEventDispatcher dispatcher(data, kcm.get()); - dispatcher.Dispatch(); - break; - } - } - MutexAutoLock lock(mQueueLock); - if (mPowerWakelock && mEventQueue.empty()) { - release_wake_lock(kKey_WAKE_LOCK_ID); - mPowerWakelock = false; - } -} - -void -GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*) -{ - gAppShell->CheckPowerKey(); -} - -void -GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args) -{ - UserInputData data; - data.timeMs = nanosecsToMillisecs(args->eventTime); - data.type = UserInputData::KEY_DATA; - data.action = args->action; - data.flags = args->flags; - data.metaState = args->metaState; - data.deviceId = args->deviceId; - data.key.keyCode = args->keyCode; - data.key.scanCode = args->scanCode; - { - MutexAutoLock lock(mQueueLock); - mEventQueue.push(data); - if (!mPowerWakelock) { - mPowerWakelock = - acquire_wake_lock(PARTIAL_WAKE_LOCK, kKey_WAKE_LOCK_ID); - } - } - gAppShell->NotifyNativeEvent(); -} - -static void -addMultiTouch(MultiTouchInput& aMultiTouch, - const NotifyMotionArgs* args, int aIndex) -{ - int32_t id = args->pointerProperties[aIndex].id; - PointerCoords coords = args->pointerCoords[aIndex]; - float force = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - - float orientation = coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - float rotationAngle = orientation * 180 / M_PI; - if (rotationAngle == 90) { - rotationAngle = -90; - } - - float radiusX, radiusY; - if (rotationAngle < 0) { - radiusX = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR) / 2; - radiusY = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR) / 2; - rotationAngle += 90; - } else { - radiusX = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR) / 2; - radiusY = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR) / 2; - } - - ScreenIntPoint point = ScreenIntPoint::Round(coords.getX(), - coords.getY()); - - SingleTouchData touchData(id, point, ScreenSize(radiusX, radiusY), - rotationAngle, force); - - aMultiTouch.mTouches.AppendElement(touchData); -} - -void -GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args) -{ - uint32_t time = nanosecsToMillisecs(args->eventTime); - int32_t action = args->action & AMOTION_EVENT_ACTION_MASK; - int touchCount = args->pointerCount; - MOZ_ASSERT(touchCount <= MAX_POINTERS); - TimeStamp timestamp = mozilla::TimeStamp::FromSystemTime(args->eventTime); - Modifiers modifiers = getDOMModifiers(args->metaState); - - MultiTouchInput::MultiTouchType touchType = MultiTouchInput::MULTITOUCH_CANCEL; - switch (action) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - touchType = MultiTouchInput::MULTITOUCH_START; - break; - case AMOTION_EVENT_ACTION_MOVE: - touchType = MultiTouchInput::MULTITOUCH_MOVE; - break; - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_POINTER_UP: - touchType = MultiTouchInput::MULTITOUCH_END; - break; - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_CANCEL: - touchType = MultiTouchInput::MULTITOUCH_CANCEL; - break; - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - NS_WARNING("Ignoring hover touch events"); - return; - default: - MOZ_ASSERT_UNREACHABLE("Could not assign a touch type"); - break; - } - - MultiTouchInput touchData(touchType, time, timestamp, modifiers); - - // For touch ends, we have to filter out which finger is actually - // the touch end since the touch array has all fingers, not just the touch - // that we want to end - if (touchType == MultiTouchInput::MULTITOUCH_END) { - int touchIndex = args->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK; - touchIndex >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - addMultiTouch(touchData, args, touchIndex); - } else { - for (int32_t i = 0; i < touchCount; ++i) { - addMultiTouch(touchData, args, i); - } - } - - mTouchDispatcher->NotifyTouch(touchData, timestamp); -} - -void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args) -{ - if (!sDevInputAudioJack) - return; - - bool needSwitchUpdate = false; - - if (args->switchMask & (1 << SW_HEADPHONE_INSERT)) { - sHeadphoneState = (args->switchValues & (1 << SW_HEADPHONE_INSERT)) ? - AKEY_STATE_DOWN : AKEY_STATE_UP; - needSwitchUpdate = true; - } - - if (args->switchMask & (1 << SW_MICROPHONE_INSERT)) { - sMicrophoneState = (args->switchValues & (1 << SW_MICROPHONE_INSERT)) ? - AKEY_STATE_DOWN : AKEY_STATE_UP; - needSwitchUpdate = true; - } - - if (needSwitchUpdate) - updateHeadphoneSwitch(); -} - -void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) -{ -} - -int32_t GeckoInputDispatcher::injectInputEvent( - const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, - int32_t timeoutMillis, uint32_t policyFlags) -{ - return INPUT_EVENT_INJECTION_SUCCEEDED; -} - -void -GeckoInputDispatcher::setInputWindows(const android::Vector<sp<InputWindowHandle> >& inputWindowHandles) -{ -} - -void -GeckoInputDispatcher::setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle) -{ -} - -void -GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen) -{ -} - -status_t -GeckoInputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel, - const sp<InputWindowHandle>& inputWindowHandle, bool monitor) -{ - return OK; -} - -status_t -GeckoInputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) -{ - return OK; -} - -nsAppShell::nsAppShell() - : mNativeCallbackRequest(false) - , mEnableDraw(false) - , mHandlers() - , mPowerKeyChecked(false) -{ - gAppShell = this; - if (XRE_IsParentProcess()) { - Preferences::SetCString("b2g.safe_mode", "unset"); - } -} - -nsAppShell::~nsAppShell() -{ - // mReaderThread and mEventHub will both be null if InitInputDevices - // is not called. - if (mReaderThread.get()) { - // We separate requestExit() and join() here so we can wake the EventHub's - // input loop, and stop it from polling for input events - mReaderThread->requestExit(); - mEventHub->wake(); - - status_t result = mReaderThread->requestExitAndWait(); - if (result) - LOG("Could not stop reader thread - %d", result); - } - gAppShell = nullptr; -} - -nsresult -nsAppShell::Init() -{ - nsresult rv = nsBaseAppShell::Init(); - NS_ENSURE_SUCCESS(rv, rv); - - epollfd = epoll_create(16); - NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED); - - int ret = pipe2(signalfds, O_NONBLOCK); - NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED); - - rv = AddFdHandler(signalfds[0], pipeHandler, ""); - NS_ENSURE_SUCCESS(rv, rv); - - InitGonkMemoryPressureMonitoring(); - - if (XRE_IsParentProcess()) { - printf("*****************************************************************\n"); - printf("***\n"); - printf("*** This is stdout. Most of the useful output will be in logcat.\n"); - printf("***\n"); - printf("*****************************************************************\n"); - GonkPermissionService::instantiate(); - - // Causes the kernel timezone to be set, which in turn causes the - // timestamps on SD cards to have the local time rather than UTC time. - hal::SetTimezone(hal::GetTimezone()); - } - - nsCOMPtr<nsIObserverService> obsServ = GetObserverService(); - if (obsServ) { - obsServ->AddObserver(this, "browser-ui-startup-complete", false); - obsServ->AddObserver(this, "network-connection-state-changed", false); - } - - // Delay initializing input devices until the screen has been - // initialized (and we know the resolution). - return rv; -} - -void -nsAppShell::CheckPowerKey() -{ - if (mPowerKeyChecked) { - return; - } - - uint32_t deviceId = 0; - int32_t powerState = AKEY_STATE_UNKNOWN; - - // EventHub doesn't report the number of devices. - while (powerState != AKEY_STATE_DOWN && deviceId < 32) { - powerState = mEventHub->getKeyCodeState(deviceId++, AKEYCODE_POWER); - } - - // If Power is pressed while we startup, mark safe mode. - // Consumers of the b2g.safe_mode preference need to listen on this - // preference change to prevent startup races. - nsCOMPtr<nsIRunnable> prefSetter = - NS_NewRunnableFunction([powerState] () -> void { - Preferences::SetCString("b2g.safe_mode", - (powerState == AKEY_STATE_DOWN) ? "yes" : "no"); - }); - NS_DispatchToMainThread(prefSetter.forget()); - - mPowerKeyChecked = true; -} - -NS_IMETHODIMP -nsAppShell::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if (!strcmp(aTopic, "network-connection-state-changed")) { - NS_ConvertUTF16toUTF8 type(aData); - if (!type.IsEmpty()) { - hal::NotifyNetworkChange(hal::NetworkInformation(atoi(type.get()), 0, 0)); - } - return NS_OK; - } else if (!strcmp(aTopic, "browser-ui-startup-complete")) { - if (sDevInputAudioJack) { - sHeadphoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT); - sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT); - updateHeadphoneSwitch(); - } - mEnableDraw = true; - - // System is almost booting up. Stop the bootAnim now. - StopBootAnimation(); - - NotifyEvent(); - return NS_OK; - } - - return nsBaseAppShell::Observe(aSubject, aTopic, aData); -} - -NS_IMETHODIMP -nsAppShell::Exit() -{ - OrientationObserver::ShutDown(); - nsCOMPtr<nsIObserverService> obsServ = GetObserverService(); - if (obsServ) { - obsServ->RemoveObserver(this, "browser-ui-startup-complete"); - obsServ->RemoveObserver(this, "network-connection-state-changed"); - } - return nsBaseAppShell::Exit(); -} - -void -nsAppShell::InitInputDevices() -{ - sDevInputAudioJack = hal::IsHeadphoneEventFromInputDev(); - sHeadphoneState = AKEY_STATE_UNKNOWN; - sMicrophoneState = AKEY_STATE_UNKNOWN; - - mEventHub = new EventHub(); - mReaderPolicy = new GeckoInputReaderPolicy(); - mReaderPolicy->setDisplayInfo(); - mDispatcher = new GeckoInputDispatcher(mEventHub); - - mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher); - mReaderThread = new InputReaderThread(mReader); - - status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); - if (result) { - LOG("Failed to initialize InputReader thread, bad things are going to happen..."); - } -} - -nsresult -nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc, - const char* deviceName) -{ - epoll_event event = { - EPOLLIN, - { 0 } - }; - - FdHandler *handler = mHandlers.AppendElement(); - handler->fd = fd; - strncpy(handler->name, deviceName, sizeof(handler->name) - 1); - handler->func = handlerFunc; - event.data.u32 = mHandlers.Length() - 1; - return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) ? - NS_ERROR_UNEXPECTED : NS_OK; -} - -void -nsAppShell::ScheduleNativeEventCallback() -{ - mNativeCallbackRequest = true; - NotifyEvent(); -} - -bool -nsAppShell::ProcessNextNativeEvent(bool mayWait) -{ - PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent", - js::ProfileEntry::Category::EVENTS); - - epoll_event events[16] = {{ 0 }}; - - int event_count; - { - PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait", - js::ProfileEntry::Category::EVENTS); - - if ((event_count = epoll_wait(epollfd, events, 16, mayWait ? -1 : 0)) <= 0) - return true; - } - - for (int i = 0; i < event_count; i++) - mHandlers[events[i].data.u32].run(); - - if (mDispatcher.get()) - mDispatcher->dispatchOnce(); - - // NativeEventCallback always schedules more if it needs it - // so we can coalesce these. - // See the implementation in nsBaseAppShell.cpp for more info - if (mNativeCallbackRequest) { - mNativeCallbackRequest = false; - NativeEventCallback(); - } - - if (gDrawRequest && mEnableDraw) { - gDrawRequest = false; - nsWindow::DoDraw(); - } - - return true; -} - -void -nsAppShell::NotifyNativeEvent() -{ - write(signalfds[1], "w", 1); -} - -/* static */ void -nsAppShell::NotifyScreenInitialized() -{ - gAppShell->InitInputDevices(); - - // Getting the instance of OrientationObserver to initialize it. - OrientationObserver::GetInstance(); -} - -/* static */ void -nsAppShell::NotifyScreenRotation() -{ - gAppShell->mReaderPolicy->setDisplayInfo(); - gAppShell->mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); - - RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); - hal::NotifyScreenConfigurationChange(screen->GetConfiguration()); -} diff --git a/widget/gonk/nsAppShell.h b/widget/gonk/nsAppShell.h deleted file mode 100644 index 046a99ea1..000000000 --- a/widget/gonk/nsAppShell.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsAppShell_h -#define nsAppShell_h - -#include <queue> - -#include "mozilla/Mutex.h" -#include "nsBaseAppShell.h" -#include "nsTArray.h" - -#include "utils/RefBase.h" - -namespace mozilla { -bool ProcessNextEvent(); -void NotifyEvent(); -} - -extern bool gDrawRequest; - -class FdHandler; -typedef void(*FdHandlerCallback)(int, FdHandler *); - -class FdHandler { -public: - FdHandler() - { - memset(name, 0, sizeof(name)); - } - - int fd; - char name[64]; - FdHandlerCallback func; - void run() - { - func(fd, this); - } -}; - -namespace android { -class EventHub; -class InputReader; -class InputReaderThread; -} - -class GeckoInputReaderPolicy; -class GeckoInputDispatcher; - -class nsAppShell : public nsBaseAppShell { -public: - nsAppShell(); - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIOBSERVER - - nsresult Init(); - - NS_IMETHOD Exit() override; - - virtual bool ProcessNextNativeEvent(bool maywait); - - void NotifyNativeEvent(); - - static void NotifyScreenInitialized(); - static void NotifyScreenRotation(); - - void CheckPowerKey(); - -protected: - virtual ~nsAppShell(); - - virtual void ScheduleNativeEventCallback(); - -private: - nsresult AddFdHandler(int fd, FdHandlerCallback handlerFunc, - const char* deviceName); - void InitInputDevices(); - - // This is somewhat racy but is perfectly safe given how the callback works - bool mNativeCallbackRequest; - - // This gets flipped when we observe a browser-ui-startup-complete. - // browser-ui-startup-complete means that we're really ready to draw - // and can stop the boot animation - bool mEnableDraw; - nsTArray<FdHandler> mHandlers; - - android::sp<android::EventHub> mEventHub; - android::sp<GeckoInputReaderPolicy> mReaderPolicy; - android::sp<GeckoInputDispatcher> mDispatcher; - android::sp<android::InputReader> mReader; - android::sp<android::InputReaderThread> mReaderThread; - - // Guard against checking power key after the first configuration change. - bool mPowerKeyChecked; -}; - -#endif /* nsAppShell_h */ - diff --git a/widget/gonk/nsClipboard.cpp b/widget/gonk/nsClipboard.cpp deleted file mode 100644 index a1eabe8e5..000000000 --- a/widget/gonk/nsClipboard.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/* 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 "nsClipboard.h" - -#include "gfxDrawable.h" -#include "gfxUtils.h" -#include "ImageOps.h" -#include "imgIContainer.h" -#include "imgTools.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/Preferences.h" -#include "nsArrayUtils.h" -#include "nsClipboardProxy.h" -#include "nsISupportsPrimitives.h" -#include "nsComponentManagerUtils.h" -#include "nsCOMPtr.h" -#include "nsServiceManagerUtils.h" -#include "nsStringStream.h" -#include "nsXULAppAPI.h" - -using namespace mozilla; -using mozilla::dom::ContentChild; - -#define LOG_TAG "Clipboard" -#define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) - - -NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard) - -nsClipboard::nsClipboard() - : mClipboard(mozilla::MakeUnique<GonkClipboardData>()) -{ -} - -NS_IMETHODIMP -nsClipboard::SetData(nsITransferable *aTransferable, - nsIClipboardOwner *anOwner, - int32_t aWhichClipboard) -{ - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - - if (!XRE_IsParentProcess()) { - // Re-direct to the clipboard proxy. - RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy(); - return clipboardProxy->SetData(aTransferable, anOwner, aWhichClipboard); - } - - // Clear out the clipboard in order to set the new data. - EmptyClipboard(aWhichClipboard); - - // Use a pref to toggle rich text/non-text support. - if (Preferences::GetBool("clipboard.plainTextOnly")) { - nsCOMPtr<nsISupports> clip; - uint32_t len; - nsresult rv = aTransferable->GetTransferData(kUnicodeMime, - getter_AddRefs(clip), - &len); - if (NS_FAILED(rv)) { - return rv; - } - nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip); - if (!wideString) { - return NS_ERROR_NOT_IMPLEMENTED; - } - nsAutoString utf16string; - wideString->GetData(utf16string); - mClipboard->SetText(utf16string); - return NS_OK; - } - - // Get the types of supported flavors. - nsCOMPtr<nsIArray> flavorList; - nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); - if (!flavorList || NS_FAILED(rv)) { - return NS_ERROR_FAILURE; - } - - uint32_t flavorCount = 0; - flavorList->GetLength(&flavorCount); - bool imageAdded = false; - for (uint32_t i = 0; i < flavorCount; ++i) { - nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i); - - if (currentFlavor) { - // MIME type - nsXPIDLCString flavorStr; - currentFlavor->ToString(getter_Copies(flavorStr)); - - // Clip is the data which will be sent to the clipboard. - nsCOMPtr<nsISupports> clip; - uint32_t len; - - if (flavorStr.EqualsLiteral(kUnicodeMime)) { - // text/plain - rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len); - nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip); - if (!wideString || NS_FAILED(rv)) { - continue; - } - - nsAutoString utf16string; - wideString->GetData(utf16string); - mClipboard->SetText(utf16string); - } else if (flavorStr.EqualsLiteral(kHTMLMime)) { - // text/html - rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len); - nsCOMPtr<nsISupportsString> wideString = do_QueryInterface(clip); - if (!wideString || NS_FAILED(rv)) { - continue; - } - - nsAutoString utf16string; - wideString->GetData(utf16string); - mClipboard->SetHTML(utf16string); - } else if (!imageAdded && // image is added only once to the clipboard. - (flavorStr.EqualsLiteral(kNativeImageMime) || - flavorStr.EqualsLiteral(kPNGImageMime) || - flavorStr.EqualsLiteral(kJPEGImageMime) || - flavorStr.EqualsLiteral(kJPGImageMime))) { - // image/[png|jpeg|jpg] or application/x-moz-nativeimage - - // Look through our transfer data for the image. - static const char* const imageMimeTypes[] = { - kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime }; - - nsCOMPtr<nsISupportsInterfacePointer> imgPtr; - for (uint32_t i = 0; !imgPtr && i < ArrayLength(imageMimeTypes); ++i) { - aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len); - imgPtr = do_QueryInterface(clip); - } - if (!imgPtr) { - continue; - } - - nsCOMPtr<nsISupports> imageData; - imgPtr->GetData(getter_AddRefs(imageData)); - nsCOMPtr<imgIContainer> image(do_QueryInterface(imageData)); - if (!image) { - continue; - } - - RefPtr<gfx::SourceSurface> surface = - image->GetFrame(imgIContainer::FRAME_CURRENT, - imgIContainer::FLAG_SYNC_DECODE); - if (!surface) { - continue; - } - - RefPtr<gfx::DataSourceSurface> dataSurface; - if (surface->GetFormat() == gfx::SurfaceFormat::B8G8R8A8) { - dataSurface = surface->GetDataSurface(); - } else { - // Convert format to SurfaceFormat::B8G8R8A8. - dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(surface, gfx::SurfaceFormat::B8G8R8A8); - } - - mClipboard->SetImage(dataSurface); - imageAdded = true; - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::GetData(nsITransferable *aTransferable, - int32_t aWhichClipboard) -{ - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - - if (!XRE_IsParentProcess()) { - // Re-direct to the clipboard proxy. - RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy(); - return clipboardProxy->GetData(aTransferable, aWhichClipboard); - } - - // Use a pref to toggle rich text/non-text support. - if (Preferences::GetBool("clipboard.plainTextOnly")) { - nsresult rv; - nsCOMPtr<nsISupportsString> dataWrapper = - do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - rv = dataWrapper->SetData(mClipboard->GetText()); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper); - uint32_t len = mClipboard->GetText().Length() * sizeof(char16_t); - rv = aTransferable->SetTransferData(kUnicodeMime, genericDataWrapper, len); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - } - - // Get flavor list that includes all acceptable flavors (including - // ones obtained through conversion). - // Note: We don't need to call nsITransferable::AddDataFlavor here - // because ContentParent already did. - nsCOMPtr<nsIArray> flavorList; - nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); - - if (!flavorList || NS_FAILED(rv)) { - return NS_ERROR_FAILURE; - } - - // Walk through flavors and see which flavor matches the one being pasted. - uint32_t flavorCount; - flavorList->GetLength(&flavorCount); - - for (uint32_t i = 0; i < flavorCount; ++i) { - nsCOMPtr<nsISupportsCString> currentFlavor = do_QueryElementAt(flavorList, i); - - if (currentFlavor) { - // flavorStr is the mime type. - nsXPIDLCString flavorStr; - currentFlavor->ToString(getter_Copies(flavorStr)); - - // text/plain, text/Unicode - if (flavorStr.EqualsLiteral(kUnicodeMime) && mClipboard->HasText()) { - nsresult rv; - nsCOMPtr<nsISupportsString> dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - rv = dataWrapper->SetData(mClipboard->GetText()); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - - nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper); - uint32_t len = mClipboard->GetText().Length() * sizeof(char16_t); - rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - break; - } - - // text/html - if (flavorStr.EqualsLiteral(kHTMLMime) && mClipboard->HasHTML()) { - nsresult rv; - nsCOMPtr<nsISupportsString> dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - rv = dataWrapper->SetData(mClipboard->GetHTML()); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - - nsCOMPtr<nsISupports> genericDataWrapper = do_QueryInterface(dataWrapper); - uint32_t len = mClipboard->GetHTML().Length() * sizeof(char16_t); - rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - break; - } - - // image/[png|jpeg|jpg] - if ((flavorStr.EqualsLiteral(kPNGImageMime) || - flavorStr.EqualsLiteral(kJPEGImageMime) || - flavorStr.EqualsLiteral(kJPGImageMime)) && - mClipboard->HasImage() ) { - // Get image buffer from clipboard. - RefPtr<gfx::DataSourceSurface> image = mClipboard->GetImage(); - - // Encode according to MIME type. - RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(image, image->GetSize()); - nsCOMPtr<imgIContainer> imageContainer(image::ImageOps::CreateFromDrawable(drawable)); - nsCOMPtr<imgITools> imgTool = do_GetService(NS_IMGTOOLS_CID); - - nsCOMPtr<nsIInputStream> byteStream; - nsresult rv = imgTool->EncodeImage(imageContainer, - flavorStr, - EmptyString(), - getter_AddRefs(byteStream)); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - - // Set transferable. - rv = aTransferable->SetTransferData(flavorStr, - byteStream, - sizeof(nsIInputStream*)); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - break; - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::EmptyClipboard(int32_t aWhichClipboard) -{ - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - if (XRE_IsParentProcess()) { - mClipboard->Clear(); - } else { - ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::HasDataMatchingFlavors(const char **aFlavorList, - uint32_t aLength, int32_t aWhichClipboard, - bool *aHasType) -{ - *aHasType = false; - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - if (XRE_IsParentProcess()) { - // Retrieve the union of all aHasType in aFlavorList - for (uint32_t i = 0; i < aLength; ++i) { - const char *flavor = aFlavorList[i]; - if (!flavor) { - continue; - } - if (!strcmp(flavor, kUnicodeMime) && mClipboard->HasText()) { - *aHasType = true; - } else if (!strcmp(flavor, kHTMLMime) && mClipboard->HasHTML()) { - *aHasType = true; - } else if (!strcmp(flavor, kJPEGImageMime) || - !strcmp(flavor, kJPGImageMime) || - !strcmp(flavor, kPNGImageMime)) { - // We will encode the image into any format you want, so we don't - // need to check each specific format - if (mClipboard->HasImage()) { - *aHasType = true; - } - } - } - } else { - RefPtr<nsClipboardProxy> clipboardProxy = new nsClipboardProxy(); - return clipboardProxy->HasDataMatchingFlavors(aFlavorList, aLength, aWhichClipboard, aHasType); - } - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::SupportsSelectionClipboard(bool *aIsSupported) -{ - *aIsSupported = false; - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::SupportsFindClipboard(bool* _retval) -{ - NS_ENSURE_ARG_POINTER(_retval); - - *_retval = false; - return NS_OK; -} - diff --git a/widget/gonk/nsClipboard.h b/widget/gonk/nsClipboard.h deleted file mode 100644 index cd2e0dbd5..000000000 --- a/widget/gonk/nsClipboard.h +++ /dev/null @@ -1,27 +0,0 @@ -/* 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/. */ - -#ifndef nsClipbard_h__ -#define nsClipbard_h__ - -#include "GonkClipboardData.h" -#include "mozilla/UniquePtr.h" -#include "nsIClipboard.h" - -class nsClipboard final : public nsIClipboard -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICLIPBOARD - - nsClipboard(); - -protected: - ~nsClipboard() {} - -private: - mozilla::UniquePtr<mozilla::GonkClipboardData> mClipboard; -}; - -#endif diff --git a/widget/gonk/nsIdleServiceGonk.cpp b/widget/gonk/nsIdleServiceGonk.cpp deleted file mode 100644 index dc7588e5e..000000000 --- a/widget/gonk/nsIdleServiceGonk.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:expandtab:shiftwidth=4:tabstop=4: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsIdleServiceGonk.h" -#include "nsIServiceManager.h" - -NS_IMPL_ISUPPORTS_INHERITED0(nsIdleServiceGonk, nsIdleService) - -bool -nsIdleServiceGonk::PollIdleTime(uint32_t *aIdleTime) -{ - return false; -} - -bool -nsIdleServiceGonk::UsePollMode() -{ - return false; -} diff --git a/widget/gonk/nsIdleServiceGonk.h b/widget/gonk/nsIdleServiceGonk.h deleted file mode 100644 index 32520dce6..000000000 --- a/widget/gonk/nsIdleServiceGonk.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:expandtab:shiftwidth=4:tabstop=4: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsIdleServiceGonk_h__ -#define nsIdleServiceGonk_h__ - -#include "nsIdleService.h" - -class nsIdleServiceGonk : public nsIdleService -{ -public: - NS_DECL_ISUPPORTS_INHERITED - - bool PollIdleTime(uint32_t* aIdleTime); - - static already_AddRefed<nsIdleServiceGonk> GetInstance() - { - RefPtr<nsIdleServiceGonk> idleService = - nsIdleService::GetInstance().downcast<nsIdleServiceGonk>(); - if (!idleService) { - idleService = new nsIdleServiceGonk(); - } - - return idleService.forget(); - } - -protected: - nsIdleServiceGonk() { } - virtual ~nsIdleServiceGonk() { } - bool UsePollMode(); -}; - -#endif // nsIdleServiceGonk_h__ diff --git a/widget/gonk/nsLookAndFeel.cpp b/widget/gonk/nsLookAndFeel.cpp deleted file mode 100644 index 120f257df..000000000 --- a/widget/gonk/nsLookAndFeel.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsLookAndFeel.h" -#include "nsStyleConsts.h" -#include "gfxFont.h" -#include "gfxFontConstants.h" -#include "mozilla/gfx/2D.h" -#include "cutils/properties.h" - -static const char16_t UNICODE_BULLET = 0x2022; - -nsLookAndFeel::nsLookAndFeel() - : nsXPLookAndFeel() -{ -} - -nsLookAndFeel::~nsLookAndFeel() -{ -} - -nsresult -nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) -{ - nsresult rv = NS_OK; - -#define BASE_ACTIVE_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define BASE_NORMAL_COLOR NS_RGB(0xff,0xff,0xff) -#define BASE_SELECTED_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define BG_ACTIVE_COLOR NS_RGB(0xff,0xff,0xff) -#define BG_INSENSITIVE_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define BG_NORMAL_COLOR NS_RGB(0xff,0xff,0xff) -#define BG_PRELIGHT_COLOR NS_RGB(0xee,0xee,0xee) -#define BG_SELECTED_COLOR NS_RGB(0x99,0x99,0x99) -#define DARK_NORMAL_COLOR NS_RGB(0x88,0x88,0x88) -#define FG_INSENSITIVE_COLOR NS_RGB(0x44,0x44,0x44) -#define FG_NORMAL_COLOR NS_RGB(0x00,0x00,0x00) -#define FG_PRELIGHT_COLOR NS_RGB(0x77,0x77,0x77) -#define FG_SELECTED_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define LIGHT_NORMAL_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define TEXT_ACTIVE_COLOR NS_RGB(0x99,0x99,0x99) -#define TEXT_NORMAL_COLOR NS_RGB(0x00,0x00,0x00) -#define TEXT_SELECTED_COLOR NS_RGB(0x00,0x00,0x00) - - switch (aID) { - // These colors don't seem to be used for anything anymore in Mozilla - // (except here at least TextSelectBackground and TextSelectForeground) - // The CSS2 colors below are used. - case eColorID_WindowBackground: - aColor = BASE_NORMAL_COLOR; - break; - case eColorID_WindowForeground: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_WidgetBackground: - aColor = BG_NORMAL_COLOR; - break; - case eColorID_WidgetForeground: - aColor = FG_NORMAL_COLOR; - break; - case eColorID_WidgetSelectBackground: - aColor = BG_SELECTED_COLOR; - break; - case eColorID_WidgetSelectForeground: - aColor = FG_SELECTED_COLOR; - break; - case eColorID_Widget3DHighlight: - aColor = NS_RGB(0xa0,0xa0,0xa0); - break; - case eColorID_Widget3DShadow: - aColor = NS_RGB(0x40,0x40,0x40); - break; - case eColorID_TextBackground: - // not used? - aColor = BASE_NORMAL_COLOR; - break; - case eColorID_TextForeground: - // not used? - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_TextSelectBackground: - aColor = NS_RGBA(0x33,0xb5,0xe5,0x66); - break; - case eColorID_IMESelectedRawTextBackground: - case eColorID_IMESelectedConvertedTextBackground: - // still used - aColor = BASE_SELECTED_COLOR; - break; - case eColorID_TextSelectForegroundCustom: - aColor = NS_RGB(0x4d,0x4d,0x4d); - break; - case eColorID_TextSelectForeground: - aColor = NS_CHANGE_COLOR_IF_SAME_AS_BG; - break; - case eColorID_IMESelectedRawTextForeground: - case eColorID_IMESelectedConvertedTextForeground: - // still used - aColor = TEXT_SELECTED_COLOR; - break; - case eColorID_IMERawInputBackground: - case eColorID_IMEConvertedTextBackground: - aColor = NS_TRANSPARENT; - break; - case eColorID_IMERawInputForeground: - case eColorID_IMEConvertedTextForeground: - aColor = NS_SAME_AS_FOREGROUND_COLOR; - break; - case eColorID_IMERawInputUnderline: - case eColorID_IMEConvertedTextUnderline: - aColor = NS_SAME_AS_FOREGROUND_COLOR; - break; - case eColorID_IMESelectedRawTextUnderline: - case eColorID_IMESelectedConvertedTextUnderline: - aColor = NS_TRANSPARENT; - break; - case eColorID_SpellCheckerUnderline: - aColor = NS_RGB(0xff, 0, 0); - break; - - // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors - case eColorID_activeborder: - // active window border - aColor = BG_NORMAL_COLOR; - break; - case eColorID_activecaption: - // active window caption background - aColor = BG_NORMAL_COLOR; - break; - case eColorID_appworkspace: - // MDI background color - aColor = BG_NORMAL_COLOR; - break; - case eColorID_background: - // desktop background - aColor = BG_NORMAL_COLOR; - break; - case eColorID_captiontext: - // text in active window caption, size box, and scrollbar arrow box (!) - aColor = FG_NORMAL_COLOR; - break; - case eColorID_graytext: - // disabled text in windows, menus, etc. - aColor = FG_INSENSITIVE_COLOR; - break; - case eColorID_highlight: - // background of selected item - aColor = BASE_SELECTED_COLOR; - break; - case eColorID_highlighttext: - // text of selected item - aColor = TEXT_SELECTED_COLOR; - break; - case eColorID_inactiveborder: - // inactive window border - aColor = BG_NORMAL_COLOR; - break; - case eColorID_inactivecaption: - // inactive window caption - aColor = BG_INSENSITIVE_COLOR; - break; - case eColorID_inactivecaptiontext: - // text in inactive window caption - aColor = FG_INSENSITIVE_COLOR; - break; - case eColorID_infobackground: - // tooltip background color - aColor = BG_NORMAL_COLOR; - break; - case eColorID_infotext: - // tooltip text color - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_menu: - // menu background - aColor = BG_NORMAL_COLOR; - break; - case eColorID_menutext: - // menu text - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_scrollbar: - // scrollbar gray area - aColor = BG_ACTIVE_COLOR; - break; - - case eColorID_threedface: - case eColorID_buttonface: - // 3-D face color - aColor = BG_NORMAL_COLOR; - break; - - case eColorID_buttontext: - // text on push buttons - aColor = TEXT_NORMAL_COLOR; - break; - - case eColorID_buttonhighlight: - // 3-D highlighted edge color - case eColorID_threedhighlight: - // 3-D highlighted outer edge color - aColor = LIGHT_NORMAL_COLOR; - break; - - case eColorID_threedlightshadow: - // 3-D highlighted inner edge color - aColor = BG_NORMAL_COLOR; - break; - - case eColorID_buttonshadow: - // 3-D shadow edge color - case eColorID_threedshadow: - // 3-D shadow inner edge color - aColor = DARK_NORMAL_COLOR; - break; - - case eColorID_threeddarkshadow: - // 3-D shadow outer edge color - aColor = NS_RGB(0,0,0); - break; - - case eColorID_window: - case eColorID_windowframe: - aColor = BG_NORMAL_COLOR; - break; - - case eColorID_windowtext: - aColor = FG_NORMAL_COLOR; - break; - - case eColorID__moz_eventreerow: - case eColorID__moz_field: - aColor = BASE_NORMAL_COLOR; - break; - case eColorID__moz_fieldtext: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID__moz_dialog: - aColor = BG_NORMAL_COLOR; - break; - case eColorID__moz_dialogtext: - aColor = FG_NORMAL_COLOR; - break; - case eColorID__moz_dragtargetzone: - aColor = BG_SELECTED_COLOR; - break; - case eColorID__moz_buttondefault: - // default button border color - aColor = NS_RGB(0,0,0); - break; - case eColorID__moz_buttonhoverface: - aColor = BG_PRELIGHT_COLOR; - break; - case eColorID__moz_buttonhovertext: - aColor = FG_PRELIGHT_COLOR; - break; - case eColorID__moz_cellhighlight: - case eColorID__moz_html_cellhighlight: - aColor = BASE_ACTIVE_COLOR; - break; - case eColorID__moz_cellhighlighttext: - case eColorID__moz_html_cellhighlighttext: - aColor = TEXT_ACTIVE_COLOR; - break; - case eColorID__moz_menuhover: - aColor = BG_PRELIGHT_COLOR; - break; - case eColorID__moz_menuhovertext: - aColor = FG_PRELIGHT_COLOR; - break; - case eColorID__moz_oddtreerow: - aColor = NS_TRANSPARENT; - break; - case eColorID__moz_nativehyperlinktext: - aColor = NS_SAME_AS_FOREGROUND_COLOR; - break; - case eColorID__moz_comboboxtext: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID__moz_combobox: - aColor = BG_NORMAL_COLOR; - break; - case eColorID__moz_menubartext: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID__moz_menubarhovertext: - aColor = FG_PRELIGHT_COLOR; - break; - default: - /* default color is BLACK */ - aColor = 0; - rv = NS_ERROR_FAILURE; - break; - } - - return rv; -} - -nsresult -nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult) -{ - nsresult rv = nsXPLookAndFeel::GetIntImpl(aID, aResult); - if (NS_SUCCEEDED(rv)) - return rv; - - rv = NS_OK; - - switch (aID) { - case eIntID_CaretBlinkTime: - aResult = 500; - break; - - case eIntID_CaretWidth: - aResult = 1; - break; - - case eIntID_ShowCaretDuringSelection: - aResult = 0; - break; - - case eIntID_SelectTextfieldsOnKeyFocus: - // Select textfield content when focused by kbd - // used by EventStateManager::sTextfieldSelectModel - aResult = 1; - break; - - case eIntID_SubmenuDelay: - aResult = 200; - break; - - case eIntID_TooltipDelay: - aResult = 500; - break; - - case eIntID_MenusCanOverlapOSBar: - // we want XUL popups to be able to overlap the task bar. - aResult = 1; - break; - - case eIntID_ScrollArrowStyle: - aResult = eScrollArrowStyle_Single; - break; - - case eIntID_ScrollSliderStyle: - aResult = eScrollThumbStyle_Proportional; - break; - - case eIntID_TouchEnabled: - aResult = 1; - break; - - case eIntID_WindowsDefaultTheme: - case eIntID_WindowsThemeIdentifier: - case eIntID_OperatingSystemVersionIdentifier: - aResult = 0; - rv = NS_ERROR_NOT_IMPLEMENTED; - break; - - case eIntID_IMERawInputUnderlineStyle: - case eIntID_IMEConvertedTextUnderlineStyle: - aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; - break; - - case eIntID_IMESelectedRawTextUnderlineStyle: - case eIntID_IMESelectedConvertedTextUnderline: - aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE; - break; - - case eIntID_SpellCheckerUnderlineStyle: - aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY; - break; - - case eIntID_ScrollbarButtonAutoRepeatBehavior: - aResult = 0; - break; - - case eIntID_PhysicalHomeButton: { - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.moz.has_home_button", propValue, "1"); - aResult = atoi(propValue); - break; - } - - case eIntID_ContextMenuOffsetVertical: - case eIntID_ContextMenuOffsetHorizontal: - aResult = 2; - break; - - default: - aResult = 0; - rv = NS_ERROR_FAILURE; - } - - return rv; -} - -nsresult -nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult) -{ - nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult); - if (NS_SUCCEEDED(res)) - return res; - res = NS_OK; - - switch (aID) { - case eFloatID_IMEUnderlineRelativeSize: - aResult = 1.0f; - break; - case eFloatID_SpellCheckerUnderlineRelativeSize: - aResult = 1.0f; - break; - default: - aResult = -1.0; - res = NS_ERROR_FAILURE; - } - return res; -} - -/*virtual*/ -bool -nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName, - gfxFontStyle& aFontStyle, - float aDevPixPerCSSPixel) -{ - aFontName.AssignLiteral("\"Fira Sans\""); - aFontStyle.style = NS_FONT_STYLE_NORMAL; - aFontStyle.weight = NS_FONT_WEIGHT_NORMAL; - aFontStyle.stretch = NS_FONT_STRETCH_NORMAL; - aFontStyle.size = 9.0 * 96.0f / 72.0f; - aFontStyle.systemFont = true; - return true; -} - -/*virtual*/ -bool -nsLookAndFeel::GetEchoPasswordImpl() { - return true; -} - -/*virtual*/ -uint32_t -nsLookAndFeel::GetPasswordMaskDelayImpl() -{ - // Same value on Android framework - return 1500; -} - -/* virtual */ -char16_t -nsLookAndFeel::GetPasswordCharacterImpl() -{ - return UNICODE_BULLET; -} diff --git a/widget/gonk/nsLookAndFeel.h b/widget/gonk/nsLookAndFeel.h deleted file mode 100644 index aa7dce823..000000000 --- a/widget/gonk/nsLookAndFeel.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef __nsLookAndFeel -#define __nsLookAndFeel - -#include "nsXPLookAndFeel.h" - -class nsLookAndFeel : public nsXPLookAndFeel -{ -public: - nsLookAndFeel(); - virtual ~nsLookAndFeel(); - - virtual bool GetFontImpl(FontID aID, nsString& aName, gfxFontStyle& aStyle, - float aDevPixPerCSSPixel); - virtual nsresult GetIntImpl(IntID aID, int32_t &aResult); - virtual nsresult GetFloatImpl(FloatID aID, float &aResult); - virtual bool GetEchoPasswordImpl(); - virtual uint32_t GetPasswordMaskDelayImpl(); - virtual char16_t GetPasswordCharacterImpl(); - -protected: - virtual nsresult NativeGetColor(ColorID aID, nscolor &aColor); -}; - -#endif diff --git a/widget/gonk/nsScreenManagerGonk.cpp b/widget/gonk/nsScreenManagerGonk.cpp deleted file mode 100644 index e359fd195..000000000 --- a/widget/gonk/nsScreenManagerGonk.cpp +++ /dev/null @@ -1,1081 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "android/log.h" -#include "GLContext.h" -#include "gfxPrefs.h" -#include "gfxUtils.h" -#include "mozilla/MouseEvents.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/Hal.h" -#include "libdisplay/BootAnimation.h" -#include "libdisplay/GonkDisplay.h" -#include "nsScreenManagerGonk.h" -#include "nsThreadUtils.h" -#include "HwcComposer2D.h" -#include "VsyncSource.h" -#include "nsWindow.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/CompositorThread.h" -#include "mozilla/Services.h" -#include "mozilla/ProcessPriorityManager.h" -#include "nsIdleService.h" -#include "nsIObserverService.h" -#include "nsAppShell.h" -#include "nsProxyRelease.h" -#include "nsTArray.h" -#include "pixelflinger/format.h" -#include "nsIDisplayInfo.h" -#include "base/task.h" - -#if ANDROID_VERSION >= 17 -#include "libdisplay/DisplaySurface.h" -#endif - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "nsScreenGonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "nsScreenGonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "nsScreenGonk", ## args) - -using namespace mozilla; -using namespace mozilla::hal; -using namespace mozilla::gfx; -using namespace mozilla::gl; -using namespace mozilla::layers; -using namespace mozilla::dom; - -namespace { - -class ScreenOnOffEvent : public mozilla::Runnable { -public: - ScreenOnOffEvent(bool on) - : mIsOn(on) - {} - - NS_IMETHOD Run() override { - // Notify observers that the screen state has just changed. - nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService(); - if (observerService) { - observerService->NotifyObservers( - nullptr, "screen-state-changed", - mIsOn ? u"on" : u"off" - ); - } - - RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); - const nsTArray<nsWindow*>& windows = screen->GetTopWindows(); - - for (uint32_t i = 0; i < windows.Length(); i++) { - nsWindow *win = windows[i]; - - if (nsIWidgetListener* listener = win->GetWidgetListener()) { - listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized); - } - } - - return NS_OK; - } - -private: - bool mIsOn; -}; - -static void -displayEnabledCallback(bool enabled) -{ - RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->DisplayEnabled(enabled); -} - -} // namespace - -static uint32_t -SurfaceFormatToColorDepth(int32_t aSurfaceFormat) -{ - switch (aSurfaceFormat) { - case GGL_PIXEL_FORMAT_RGB_565: - return 16; - case GGL_PIXEL_FORMAT_RGBA_8888: - return 32; - } - return 24; // GGL_PIXEL_FORMAT_RGBX_8888 -} - -// nsScreenGonk.cpp - -nsScreenGonk::nsScreenGonk(uint32_t aId, - GonkDisplay::DisplayType aDisplayType, - const GonkDisplay::NativeData& aNativeData, - NotifyDisplayChangedEvent aEventVisibility) - : mId(aId) - , mEventVisibility(aEventVisibility) - , mNativeWindow(aNativeData.mNativeWindow) - , mDpi(aNativeData.mXdpi) - , mScreenRotation(nsIScreen::ROTATION_0_DEG) - , mPhysicalScreenRotation(nsIScreen::ROTATION_0_DEG) -#if ANDROID_VERSION >= 17 - , mDisplaySurface(aNativeData.mDisplaySurface) -#endif - , mIsMirroring(false) - , mDisplayType(aDisplayType) - , mEGLDisplay(EGL_NO_DISPLAY) - , mEGLSurface(EGL_NO_SURFACE) - , mGLContext(nullptr) - , mFramebuffer(nullptr) - , mMappedBuffer(nullptr) -{ - if (mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &mVirtualBounds.width) || - mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &mVirtualBounds.height) || - mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FORMAT, &mSurfaceFormat)) { - NS_RUNTIMEABORT("Failed to get native window size, aborting..."); - } - - mNaturalBounds = mVirtualBounds; - - if (IsPrimaryScreen()) { - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.sf.hwrotation", propValue, "0"); - mPhysicalScreenRotation = atoi(propValue) / 90; - } - - mColorDepth = SurfaceFormatToColorDepth(mSurfaceFormat); -} - -static void -ReleaseGLContextSync(mozilla::gl::GLContext* aGLContext) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - aGLContext->Release(); -} - -nsScreenGonk::~nsScreenGonk() -{ - // Release GLContext on compositor thread - if (mGLContext) { - CompositorThreadHolder::Loop()->PostTask( - NewRunnableFunction(&ReleaseGLContextSync, - mGLContext.forget().take())); - mGLContext = nullptr; - } -} - -bool -nsScreenGonk::IsPrimaryScreen() -{ - return mDisplayType == GonkDisplay::DISPLAY_PRIMARY; -} - -NS_IMETHODIMP -nsScreenGonk::GetId(uint32_t *outId) -{ - *outId = mId; - return NS_OK; -} - -uint32_t -nsScreenGonk::GetId() -{ - return mId; -} - -NotifyDisplayChangedEvent -nsScreenGonk::GetEventVisibility() -{ - return mEventVisibility; -} - -NS_IMETHODIMP -nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop, - int32_t *outWidth, int32_t *outHeight) -{ - *outLeft = mVirtualBounds.x; - *outTop = mVirtualBounds.y; - - *outWidth = mVirtualBounds.width; - *outHeight = mVirtualBounds.height; - - return NS_OK; -} - -LayoutDeviceIntRect -nsScreenGonk::GetRect() -{ - return mVirtualBounds; -} - -NS_IMETHODIMP -nsScreenGonk::GetAvailRect(int32_t *outLeft, int32_t *outTop, - int32_t *outWidth, int32_t *outHeight) -{ - return GetRect(outLeft, outTop, outWidth, outHeight); -} - -NS_IMETHODIMP -nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth) -{ - // XXX: this should actually return 32 when we're using 24-bit - // color, because we use RGBX. - *aPixelDepth = mColorDepth; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenGonk::GetColorDepth(int32_t *aColorDepth) -{ - *aColorDepth = mColorDepth; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenGonk::GetRotation(uint32_t* aRotation) -{ - *aRotation = mScreenRotation; - return NS_OK; -} - -float -nsScreenGonk::GetDpi() -{ - return mDpi; -} - -int32_t -nsScreenGonk::GetSurfaceFormat() -{ - return mSurfaceFormat; -} - -ANativeWindow* -nsScreenGonk::GetNativeWindow() -{ - return mNativeWindow.get(); -} - -NS_IMETHODIMP -nsScreenGonk::SetRotation(uint32_t aRotation) -{ - if (!(aRotation <= ROTATION_270_DEG)) { - return NS_ERROR_ILLEGAL_VALUE; - } - - if (mScreenRotation == aRotation) { - return NS_OK; - } - - mScreenRotation = aRotation; - uint32_t rotation = EffectiveScreenRotation(); - if (rotation == nsIScreen::ROTATION_90_DEG || - rotation == nsIScreen::ROTATION_270_DEG) { - mVirtualBounds = LayoutDeviceIntRect(0, 0, - mNaturalBounds.height, - mNaturalBounds.width); - } else { - mVirtualBounds = mNaturalBounds; - } - - nsAppShell::NotifyScreenRotation(); - - for (unsigned int i = 0; i < mTopWindows.Length(); i++) { - mTopWindows[i]->Resize(mVirtualBounds.width, - mVirtualBounds.height, - true); - } - - return NS_OK; -} - -LayoutDeviceIntRect -nsScreenGonk::GetNaturalBounds() -{ - return mNaturalBounds; -} - -uint32_t -nsScreenGonk::EffectiveScreenRotation() -{ - return (mScreenRotation + mPhysicalScreenRotation) % (360 / 90); -} - -// NB: This isn't gonk-specific, but gonk is the only widget backend -// that does this calculation itself, currently. -static ScreenOrientationInternal -ComputeOrientation(uint32_t aRotation, const LayoutDeviceIntSize& aScreenSize) -{ - bool naturallyPortrait = (aScreenSize.height > aScreenSize.width); - switch (aRotation) { - case nsIScreen::ROTATION_0_DEG: - return (naturallyPortrait ? eScreenOrientation_PortraitPrimary : - eScreenOrientation_LandscapePrimary); - case nsIScreen::ROTATION_90_DEG: - // Arbitrarily choosing 90deg to be primary "unnatural" - // rotation. - return (naturallyPortrait ? eScreenOrientation_LandscapePrimary : - eScreenOrientation_PortraitPrimary); - case nsIScreen::ROTATION_180_DEG: - return (naturallyPortrait ? eScreenOrientation_PortraitSecondary : - eScreenOrientation_LandscapeSecondary); - case nsIScreen::ROTATION_270_DEG: - return (naturallyPortrait ? eScreenOrientation_LandscapeSecondary : - eScreenOrientation_PortraitSecondary); - default: - MOZ_CRASH("Gonk screen must always have a known rotation"); - } -} - -static uint16_t -RotationToAngle(uint32_t aRotation) -{ - uint16_t angle = 90 * aRotation; - MOZ_ASSERT(angle == 0 || angle == 90 || angle == 180 || angle == 270); - return angle; -} - -ScreenConfiguration -nsScreenGonk::GetConfiguration() -{ - ScreenOrientationInternal orientation = - ComputeOrientation(mScreenRotation, mNaturalBounds.Size()); - - // NB: perpetuating colorDepth == pixelDepth illusion here, for - // consistency. - return ScreenConfiguration(mVirtualBounds.ToUnknownRect(), orientation, - RotationToAngle(mScreenRotation), - mColorDepth, mColorDepth); -} - -void -nsScreenGonk::RegisterWindow(nsWindow* aWindow) -{ - mTopWindows.AppendElement(aWindow); -} - -void -nsScreenGonk::UnregisterWindow(nsWindow* aWindow) -{ - mTopWindows.RemoveElement(aWindow); -} - -void -nsScreenGonk::BringToTop(nsWindow* aWindow) -{ - mTopWindows.RemoveElement(aWindow); - mTopWindows.InsertElementAt(0, aWindow); -} - -static gralloc_module_t const* -gralloc_module() -{ - hw_module_t const *module; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) { - return nullptr; - } - return reinterpret_cast<gralloc_module_t const*>(module); -} - -static SurfaceFormat -HalFormatToSurfaceFormat(int aHalFormat) -{ - switch (aHalFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - // Needs RB swap - return SurfaceFormat::B8G8R8A8; - case HAL_PIXEL_FORMAT_RGBX_8888: - // Needs RB swap - return SurfaceFormat::B8G8R8X8; - case HAL_PIXEL_FORMAT_BGRA_8888: - return SurfaceFormat::B8G8R8A8; - case HAL_PIXEL_FORMAT_RGB_565: - return SurfaceFormat::R5G6B5_UINT16; - default: - MOZ_CRASH("Unhandled HAL pixel format"); - return SurfaceFormat::UNKNOWN; // not reached - } -} - -static bool -NeedsRBSwap(int aHalFormat) -{ - switch (aHalFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - return true; - case HAL_PIXEL_FORMAT_RGBX_8888: - return true; - case HAL_PIXEL_FORMAT_BGRA_8888: - return false; - case HAL_PIXEL_FORMAT_RGB_565: - return false; - default: - MOZ_CRASH("Unhandled HAL pixel format"); - return false; // not reached - } -} - -already_AddRefed<DrawTarget> -nsScreenGonk::StartRemoteDrawing() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(!mFramebuffer); - MOZ_ASSERT(!mMappedBuffer); - - mFramebuffer = DequeueBuffer(); - int width = mFramebuffer->width, height = mFramebuffer->height; - if (gralloc_module()->lock(gralloc_module(), mFramebuffer->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, width, height, - reinterpret_cast<void**>(&mMappedBuffer))) { - EndRemoteDrawing(); - return nullptr; - } - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - mFramebufferTarget = Factory::CreateDrawTargetForData( - BackendType::CAIRO, - mMappedBuffer, - IntSize(width, height), - mFramebuffer->stride * gfx::BytesPerPixel(format), - format); - if (!mFramebufferTarget) { - MOZ_CRASH("nsWindow::StartRemoteDrawing failed in CreateDrawTargetForData"); - } - if (!mBackBuffer || - mBackBuffer->GetSize() != mFramebufferTarget->GetSize() || - mBackBuffer->GetFormat() != mFramebufferTarget->GetFormat()) { - mBackBuffer = mFramebufferTarget->CreateSimilarDrawTarget( - mFramebufferTarget->GetSize(), mFramebufferTarget->GetFormat()); - } - RefPtr<DrawTarget> buffer(mBackBuffer); - return buffer.forget(); -} - -void -nsScreenGonk::EndRemoteDrawing() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - - if (mFramebufferTarget && mFramebuffer) { - IntSize size = mFramebufferTarget->GetSize(); - Rect rect(0, 0, size.width, size.height); - RefPtr<SourceSurface> source = mBackBuffer->Snapshot(); - mFramebufferTarget->DrawSurface(source, rect, rect); - - // Convert from BGR to RGB - // XXX this is a temporary solution. It consumes extra cpu cycles, - // it should not be used on product device. - if (NeedsRBSwap(GetSurfaceFormat())) { - LOGE("Very slow composition path, it should not be used on product!!!"); - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - gfxUtils::ConvertBGRAtoRGBA( - mMappedBuffer, - mFramebuffer->stride * mFramebuffer->height * gfx::BytesPerPixel(format)); - } - } - if (mMappedBuffer) { - MOZ_ASSERT(mFramebuffer); - gralloc_module()->unlock(gralloc_module(), mFramebuffer->handle); - mMappedBuffer = nullptr; - } - if (mFramebuffer) { - QueueBuffer(mFramebuffer); - } - mFramebuffer = nullptr; - mFramebufferTarget = nullptr; -} - -ANativeWindowBuffer* -nsScreenGonk::DequeueBuffer() -{ - ANativeWindowBuffer* buf = nullptr; -#if ANDROID_VERSION >= 17 - int fenceFd = -1; - mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd); - android::sp<android::Fence> fence(new android::Fence(fenceFd)); -#if ANDROID_VERSION == 17 - fence->waitForever(1000, "nsScreenGonk_DequeueBuffer"); - // 1000 is what Android uses. It is a warning timeout in ms. - // This timeout was removed in ANDROID_VERSION 18. -#else - fence->waitForever("nsScreenGonk_DequeueBuffer"); -#endif -#else - mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf); -#endif - return buf; -} - -bool -nsScreenGonk::QueueBuffer(ANativeWindowBuffer* buf) -{ -#if ANDROID_VERSION >= 17 - int ret = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1); - return ret == 0; -#else - int ret = mNativeWindow->queueBuffer(mNativeWindow.get(), buf); - return ret == 0; -#endif -} - -nsresult -nsScreenGonk::MakeSnapshot(ANativeWindowBuffer* aBuffer) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(aBuffer); - - layers::CompositorBridgeParent* compositorParent = mCompositorBridgeParent; - if (!compositorParent) { - return NS_ERROR_FAILURE; - } - - int width = aBuffer->width, height = aBuffer->height; - uint8_t* mappedBuffer = nullptr; - if (gralloc_module()->lock(gralloc_module(), aBuffer->handle, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN, - 0, 0, width, height, - reinterpret_cast<void**>(&mappedBuffer))) { - return NS_ERROR_FAILURE; - } - - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - RefPtr<DrawTarget> mTarget = - Factory::CreateDrawTargetForData( - BackendType::CAIRO, - mappedBuffer, - IntSize(width, height), - aBuffer->stride * gfx::BytesPerPixel(format), - format); - if (!mTarget) { - return NS_ERROR_FAILURE; - } - - gfx::IntRect rect = GetRect().ToUnknownRect(); - compositorParent->ForceComposeToTarget(mTarget, &rect); - - // Convert from BGR to RGB - // XXX this is a temporary solution. It consumes extra cpu cycles, - if (NeedsRBSwap(GetSurfaceFormat())) { - LOGE("Slow path of making Snapshot!!!"); - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - gfxUtils::ConvertBGRAtoRGBA( - mappedBuffer, - aBuffer->stride * aBuffer->height * gfx::BytesPerPixel(format)); - mappedBuffer = nullptr; - } - gralloc_module()->unlock(gralloc_module(), aBuffer->handle); - return NS_OK; -} - -void -nsScreenGonk::SetCompositorBridgeParent(layers::CompositorBridgeParent* aCompositorBridgeParent) -{ - MOZ_ASSERT(NS_IsMainThread()); - mCompositorBridgeParent = aCompositorBridgeParent; -} - -#if ANDROID_VERSION >= 17 -android::DisplaySurface* -nsScreenGonk::GetDisplaySurface() -{ - return mDisplaySurface.get(); -} - -int -nsScreenGonk::GetPrevDispAcquireFd() -{ - if (!mDisplaySurface.get()) { - return -1; - } - return mDisplaySurface->GetPrevDispAcquireFd(); -} -#endif - -GonkDisplay::DisplayType -nsScreenGonk::GetDisplayType() -{ - return mDisplayType; -} - -void -nsScreenGonk::SetEGLInfo(hwc_display_t aDisplay, - hwc_surface_t aSurface, - gl::GLContext* aGLContext) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - mEGLDisplay = aDisplay; - mEGLSurface = aSurface; - mGLContext = aGLContext; -} - -hwc_display_t -nsScreenGonk::GetEGLDisplay() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - return mEGLDisplay; -} - -hwc_surface_t -nsScreenGonk::GetEGLSurface() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - return mEGLSurface; -} - -already_AddRefed<mozilla::gl::GLContext> -nsScreenGonk::GetGLContext() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - RefPtr<mozilla::gl::GLContext>glContext = mGLContext; - return glContext.forget(); -} - -static void -UpdateMirroringWidgetSync(nsMainThreadPtrHandle<nsScreenGonk>&& aScreen, nsWindow* aWindow) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - already_AddRefed<nsWindow> window(aWindow); - aScreen->UpdateMirroringWidget(window); -} - -bool -nsScreenGonk::EnableMirroring() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!IsPrimaryScreen()); - - RefPtr<nsScreenGonk> primaryScreen = nsScreenManagerGonk::GetPrimaryScreen(); - NS_ENSURE_TRUE(primaryScreen, false); - - bool ret = primaryScreen->SetMirroringScreen(this); - NS_ENSURE_TRUE(ret, false); - - // Create a widget for mirroring - nsWidgetInitData initData; - initData.mScreenId = mId; - RefPtr<nsWindow> window = new nsWindow(); - nsresult rv = window->Create(nullptr, nullptr, mNaturalBounds, &initData); - NS_ENSURE_SUCCESS(rv, false); - MOZ_ASSERT(static_cast<nsWindow*>(window)->GetScreen() == this); - - // Update mMirroringWidget on compositor thread - nsMainThreadPtrHandle<nsScreenGonk> primary = - nsMainThreadPtrHandle<nsScreenGonk>(new nsMainThreadPtrHolder<nsScreenGonk>(primaryScreen, false)); - CompositorThreadHolder::Loop()->PostTask( - NewRunnableFunction(&UpdateMirroringWidgetSync, - primary, - window.forget().take())); - - mIsMirroring = true; - return true; -} - -bool -nsScreenGonk::DisableMirroring() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!IsPrimaryScreen()); - - mIsMirroring = false; - RefPtr<nsScreenGonk> primaryScreen = nsScreenManagerGonk::GetPrimaryScreen(); - NS_ENSURE_TRUE(primaryScreen, false); - - bool ret = primaryScreen->ClearMirroringScreen(this); - NS_ENSURE_TRUE(ret, false); - - // Update mMirroringWidget on compositor thread - nsMainThreadPtrHandle<nsScreenGonk> primary = - nsMainThreadPtrHandle<nsScreenGonk>(new nsMainThreadPtrHolder<nsScreenGonk>(primaryScreen, false)); - CompositorThreadHolder::Loop()->PostTask( - NewRunnableFunction(&UpdateMirroringWidgetSync, - primary, - nullptr)); - return true; -} - -bool -nsScreenGonk::SetMirroringScreen(nsScreenGonk* aScreen) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - if (mMirroringScreen) { - return false; - } - mMirroringScreen = aScreen; - return true; -} - -bool -nsScreenGonk::ClearMirroringScreen(nsScreenGonk* aScreen) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - if (mMirroringScreen != aScreen) { - return false; - } - mMirroringScreen = nullptr; - return true; -} - -void -nsScreenGonk::UpdateMirroringWidget(already_AddRefed<nsWindow>& aWindow) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - if (mMirroringWidget) { - nsCOMPtr<nsIWidget> widget = mMirroringWidget.forget(); - NS_ReleaseOnMainThread(widget.forget()); - } - mMirroringWidget = aWindow; -} - -nsWindow* -nsScreenGonk::GetMirroringWidget() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - return mMirroringWidget; -} - -NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager) - -nsScreenManagerGonk::nsScreenManagerGonk() - : mInitialized(false) -#if ANDROID_VERSION >= 19 - , mDisplayEnabled(false) -#endif -{ -} - -nsScreenManagerGonk::~nsScreenManagerGonk() -{ -} - -static StaticRefPtr<nsScreenManagerGonk> sScreenManagerGonk; - -/* static */ already_AddRefed<nsScreenManagerGonk> -nsScreenManagerGonk::GetInstance() -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Avoid creating nsScreenManagerGonk from content process. - if (!XRE_IsParentProcess()) { - MOZ_CRASH("Non-chrome processes should not get here."); - } - - // Avoid creating multiple nsScreenManagerGonk instance inside main process. - if (!sScreenManagerGonk) { - sScreenManagerGonk = new nsScreenManagerGonk(); - ClearOnShutdown(&sScreenManagerGonk); - } - - RefPtr<nsScreenManagerGonk> screenMgr = sScreenManagerGonk.get(); - return screenMgr.forget(); -} - -/* static */ already_AddRefed< nsScreenGonk> -nsScreenManagerGonk::GetPrimaryScreen() -{ - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr<nsScreenManagerGonk> manager = nsScreenManagerGonk::GetInstance(); - nsCOMPtr<nsIScreen> screen; - manager->GetPrimaryScreen(getter_AddRefs(screen)); - MOZ_ASSERT(screen); - return already_AddRefed<nsScreenGonk>( - static_cast<nsScreenGonk*>(screen.forget().take())); -} - -void -nsScreenManagerGonk::Initialize() -{ - if (mInitialized) { - return; - } - - mScreenOnEvent = new ScreenOnOffEvent(true); - mScreenOffEvent = new ScreenOnOffEvent(false); - GetGonkDisplay()->OnEnabled(displayEnabledCallback); - - AddScreen(GonkDisplay::DISPLAY_PRIMARY); - - nsAppShell::NotifyScreenInitialized(); - mInitialized = true; -} - -void -nsScreenManagerGonk::DisplayEnabled(bool aEnabled) -{ - MOZ_ASSERT(NS_IsMainThread()); - -#if ANDROID_VERSION >= 19 - /* Bug 1244044 - * This function could be called before |mCompositorVsyncScheduler| is set. - * To avoid this issue, keep the value stored in |mDisplayEnabled|. - */ - mDisplayEnabled = aEnabled; - if (mCompositorVsyncScheduler) { - mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled); - } -#endif - - VsyncControl(aEnabled); - NS_DispatchToMainThread(aEnabled ? mScreenOnEvent : mScreenOffEvent); -} - -NS_IMETHODIMP -nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen) -{ - NS_IF_ADDREF(*outScreen = mScreens[0].get()); - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForId(uint32_t aId, - nsIScreen **outScreen) -{ - for (size_t i = 0; i < mScreens.Length(); i++) { - if (mScreens[i]->GetId() == aId) { - NS_IF_ADDREF(*outScreen = mScreens[i].get()); - return NS_OK; - } - } - - *outScreen = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForRect(int32_t inLeft, - int32_t inTop, - int32_t inWidth, - int32_t inHeight, - nsIScreen **outScreen) -{ - // Since all screens have independent coordinate system, we could - // only return the primary screen no matter what rect is given. - return GetPrimaryScreen(outScreen); -} - -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen) -{ - for (size_t i = 0; i < mScreens.Length(); i++) { - if (aWidget == mScreens[i]->GetNativeWindow()) { - NS_IF_ADDREF(*outScreen = mScreens[i].get()); - return NS_OK; - } - } - - *outScreen = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens) -{ - *aNumberOfScreens = mScreens.Length(); - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale) -{ - *aDefaultScale = 1.0f; - return NS_OK; -} - -void -nsScreenManagerGonk::VsyncControl(bool aEnabled) -{ - if (!NS_IsMainThread()) { - NS_DispatchToMainThread( - NewRunnableMethod<bool>(this, - &nsScreenManagerGonk::VsyncControl, - aEnabled)); - return; - } - - MOZ_ASSERT(NS_IsMainThread()); - VsyncSource::Display &display = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay(); - if (aEnabled) { - display.EnableVsync(); - } else { - display.DisableVsync(); - } -} - -uint32_t -nsScreenManagerGonk::GetIdFromType(GonkDisplay::DisplayType aDisplayType) -{ - // This is the only place where we make the assumption that - // display type is equivalent to screen id. - - // Bug 1138287 will address the conversion from type to id. - return aDisplayType; -} - -bool -nsScreenManagerGonk::IsScreenConnected(uint32_t aId) -{ - for (size_t i = 0; i < mScreens.Length(); ++i) { - if (mScreens[i]->GetId() == aId) { - return true; - } - } - - return false; -} - -namespace { - -// A concrete class as a subject for 'display-changed' observer event. -class DisplayInfo : public nsIDisplayInfo { -public: - NS_DECL_ISUPPORTS - - DisplayInfo(uint32_t aId, bool aConnected) - : mId(aId) - , mConnected(aConnected) - { - } - - NS_IMETHODIMP GetId(int32_t *aId) - { - *aId = mId; - return NS_OK; - } - - NS_IMETHODIMP GetConnected(bool *aConnected) - { - *aConnected = mConnected; - return NS_OK; - } - -private: - virtual ~DisplayInfo() {} - - uint32_t mId; - bool mConnected; -}; - -NS_IMPL_ISUPPORTS(DisplayInfo, nsIDisplayInfo, nsISupports) - -class NotifyTask : public mozilla::Runnable { -public: - NotifyTask(uint32_t aId, bool aConnected) - : mDisplayInfo(new DisplayInfo(aId, aConnected)) - { - } - - NS_IMETHOD Run() override - { - nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService(); - if (os) { - os->NotifyObservers(mDisplayInfo, "display-changed", nullptr); - } - - return NS_OK; - } -private: - RefPtr<DisplayInfo> mDisplayInfo; -}; - -void -NotifyDisplayChange(uint32_t aId, bool aConnected) -{ - NS_DispatchToMainThread(new NotifyTask(aId, aConnected)); -} - -} // end of unnamed namespace. - -nsresult -nsScreenManagerGonk::AddScreen(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink, - NotifyDisplayChangedEvent aEventVisibility) -{ - MOZ_ASSERT(NS_IsMainThread()); - - NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES, - NS_ERROR_FAILURE); - - uint32_t id = GetIdFromType(aDisplayType); - NS_ENSURE_TRUE(!IsScreenConnected(id), NS_ERROR_FAILURE); - - GonkDisplay::NativeData nativeData = - GetGonkDisplay()->GetNativeData(aDisplayType, aSink); - nsScreenGonk* screen = new nsScreenGonk(id, - aDisplayType, - nativeData, - aEventVisibility); - mScreens.AppendElement(screen); - - if (aEventVisibility == NotifyDisplayChangedEvent::Observable) { - NotifyDisplayChange(id, true); - } - - // By default, non primary screen does mirroring. - if (aDisplayType != GonkDisplay::DISPLAY_PRIMARY && - gfxPrefs::ScreenMirroringEnabled()) { - screen->EnableMirroring(); - } - - return NS_OK; -} - -nsresult -nsScreenManagerGonk::RemoveScreen(GonkDisplay::DisplayType aDisplayType) -{ - MOZ_ASSERT(NS_IsMainThread()); - - NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES, - NS_ERROR_FAILURE); - - NotifyDisplayChangedEvent eventVisibility = NotifyDisplayChangedEvent::Observable; - uint32_t screenId = GetIdFromType(aDisplayType); - NS_ENSURE_TRUE(IsScreenConnected(screenId), NS_ERROR_FAILURE); - - for (size_t i = 0; i < mScreens.Length(); i++) { - if (mScreens[i]->GetId() == screenId) { - if (mScreens[i]->IsMirroring()) { - mScreens[i]->DisableMirroring(); - } - eventVisibility = mScreens[i]->GetEventVisibility(); - mScreens.RemoveElementAt(i); - break; - } - } - - if (eventVisibility == NotifyDisplayChangedEvent::Observable) { - NotifyDisplayChange(screenId, false); - } - return NS_OK; -} - -#if ANDROID_VERSION >= 19 -void -nsScreenManagerGonk::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver) -{ - MOZ_ASSERT(NS_IsMainThread()); - - // We assume on b2g that there is only 1 CompositorBridgeParent - MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); - MOZ_ASSERT(aObserver); - mCompositorVsyncScheduler = aObserver; - mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled); -} -#endif diff --git a/widget/gonk/nsScreenManagerGonk.h b/widget/gonk/nsScreenManagerGonk.h deleted file mode 100644 index 33ef5edb8..000000000 --- a/widget/gonk/nsScreenManagerGonk.h +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsScreenManagerGonk_h___ -#define nsScreenManagerGonk_h___ - -#include "cutils/properties.h" -#include "hardware/hwcomposer.h" - -#include "libdisplay/GonkDisplay.h" -#include "mozilla/Atomics.h" -#include "mozilla/Hal.h" -#include "mozilla/Mutex.h" -#include "nsBaseScreen.h" -#include "nsCOMPtr.h" -#include "nsIScreenManager.h" -#include "nsProxyRelease.h" - -#include <android/native_window.h> - -class nsWindow; - -namespace android { - class DisplaySurface; - class IGraphicBufferProducer; -}; - -namespace mozilla { - class Runnable; -namespace gl { - class GLContext; -} -namespace layers { -class CompositorVsyncScheduler; -class CompositorBridgeParent; -} -} - -enum class NotifyDisplayChangedEvent : int8_t { - Observable, - Suppressed -}; - -class nsScreenGonk : public nsBaseScreen -{ - typedef mozilla::hal::ScreenConfiguration ScreenConfiguration; - typedef mozilla::GonkDisplay GonkDisplay; - typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; - typedef mozilla::layers::CompositorBridgeParent CompositorBridgeParent; - typedef mozilla::gfx::DrawTarget DrawTarget; - -public: - nsScreenGonk(uint32_t aId, - GonkDisplay::DisplayType aDisplayType, - const GonkDisplay::NativeData& aNativeData, - NotifyDisplayChangedEvent aEventVisibility); - - ~nsScreenGonk(); - - NS_IMETHOD GetId(uint32_t* aId); - NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); - NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); - NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); - NS_IMETHOD GetColorDepth(int32_t* aColorDepth); - NS_IMETHOD GetRotation(uint32_t* aRotation); - NS_IMETHOD SetRotation(uint32_t aRotation); - - uint32_t GetId(); - NotifyDisplayChangedEvent GetEventVisibility(); - LayoutDeviceIntRect GetRect(); - float GetDpi(); - int32_t GetSurfaceFormat(); - ANativeWindow* GetNativeWindow(); - LayoutDeviceIntRect GetNaturalBounds(); - uint32_t EffectiveScreenRotation(); - ScreenConfiguration GetConfiguration(); - bool IsPrimaryScreen(); - - already_AddRefed<DrawTarget> StartRemoteDrawing(); - void EndRemoteDrawing(); - - nsresult MakeSnapshot(ANativeWindowBuffer* aBuffer); - void SetCompositorBridgeParent(CompositorBridgeParent* aCompositorBridgeParent); - -#if ANDROID_VERSION >= 17 - android::DisplaySurface* GetDisplaySurface(); - int GetPrevDispAcquireFd(); -#endif - GonkDisplay::DisplayType GetDisplayType(); - - void RegisterWindow(nsWindow* aWindow); - void UnregisterWindow(nsWindow* aWindow); - void BringToTop(nsWindow* aWindow); - - const nsTArray<nsWindow*>& GetTopWindows() const - { - return mTopWindows; - } - - // Non-primary screen only - bool EnableMirroring(); - bool DisableMirroring(); - bool IsMirroring() - { - return mIsMirroring; - } - - // Primary screen only - bool SetMirroringScreen(nsScreenGonk* aScreen); - bool ClearMirroringScreen(nsScreenGonk* aScreen); - - // Called only on compositor thread - void SetEGLInfo(hwc_display_t aDisplay, hwc_surface_t aSurface, - mozilla::gl::GLContext* aGLContext); - hwc_display_t GetEGLDisplay(); - hwc_surface_t GetEGLSurface(); - already_AddRefed<mozilla::gl::GLContext> GetGLContext(); - void UpdateMirroringWidget(already_AddRefed<nsWindow>& aWindow); // Primary screen only - nsWindow* GetMirroringWidget(); // Primary screen only - -protected: - ANativeWindowBuffer* DequeueBuffer(); - bool QueueBuffer(ANativeWindowBuffer* buf); - - uint32_t mId; - NotifyDisplayChangedEvent mEventVisibility; - int32_t mColorDepth; - android::sp<ANativeWindow> mNativeWindow; - float mDpi; - int32_t mSurfaceFormat; - LayoutDeviceIntRect mNaturalBounds; // Screen bounds w/o rotation taken into account. - LayoutDeviceIntRect mVirtualBounds; // Screen bounds w/ rotation taken into account. - uint32_t mScreenRotation; - uint32_t mPhysicalScreenRotation; - nsTArray<nsWindow*> mTopWindows; -#if ANDROID_VERSION >= 17 - android::sp<android::DisplaySurface> mDisplaySurface; -#endif - bool mIsMirroring; // Non-primary screen only - RefPtr<nsScreenGonk> mMirroringScreen; // Primary screen only - mozilla::Atomic<CompositorBridgeParent*> mCompositorBridgeParent; - - // Accessed and updated only on compositor thread - GonkDisplay::DisplayType mDisplayType; - hwc_display_t mEGLDisplay; - hwc_surface_t mEGLSurface; - RefPtr<mozilla::gl::GLContext> mGLContext; - RefPtr<nsWindow> mMirroringWidget; // Primary screen only - - // If we're using a BasicCompositor, these fields are temporarily - // set during frame composition. They wrap the hardware - // framebuffer. - RefPtr<DrawTarget> mFramebufferTarget; - ANativeWindowBuffer* mFramebuffer; - /** - * Points to a mapped gralloc buffer between calls to lock and unlock. - * Should be null outside of the lock-unlock pair. - */ - uint8_t* mMappedBuffer; - // If we're using a BasicCompositor, this is our window back - // buffer. The gralloc framebuffer driver expects us to draw the - // entire framebuffer on every frame, but gecko expects the - // windowing system to be tracking buffer updates for invalidated - // regions. We get stuck holding that bag. - // - // Only accessed on the compositor thread, except during - // destruction. - RefPtr<DrawTarget> mBackBuffer; -}; - -class nsScreenManagerGonk final : public nsIScreenManager -{ -public: - typedef mozilla::GonkDisplay GonkDisplay; - -public: - nsScreenManagerGonk(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISCREENMANAGER - - static already_AddRefed<nsScreenManagerGonk> GetInstance(); - static already_AddRefed<nsScreenGonk> GetPrimaryScreen(); - - void Initialize(); - void DisplayEnabled(bool aEnabled); - - nsresult AddScreen(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink = nullptr, - NotifyDisplayChangedEvent aEventVisibility = NotifyDisplayChangedEvent::Observable); - - nsresult RemoveScreen(GonkDisplay::DisplayType aDisplayType); - -#if ANDROID_VERSION >= 19 - void SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler* aObserver); -#endif - -protected: - ~nsScreenManagerGonk(); - void VsyncControl(bool aEnabled); - uint32_t GetIdFromType(GonkDisplay::DisplayType aDisplayType); - bool IsScreenConnected(uint32_t aId); - - bool mInitialized; - nsTArray<RefPtr<nsScreenGonk>> mScreens; - RefPtr<mozilla::Runnable> mScreenOnEvent; - RefPtr<mozilla::Runnable> mScreenOffEvent; - -#if ANDROID_VERSION >= 19 - bool mDisplayEnabled; - RefPtr<mozilla::layers::CompositorVsyncScheduler> mCompositorVsyncScheduler; -#endif -}; - -#endif /* nsScreenManagerGonk_h___ */ diff --git a/widget/gonk/nsWidgetFactory.cpp b/widget/gonk/nsWidgetFactory.cpp deleted file mode 100644 index 1c7525544..000000000 --- a/widget/gonk/nsWidgetFactory.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "base/basictypes.h" - -#include "mozilla/ModuleUtils.h" -#include "mozilla/WidgetUtils.h" - -#include "nsCOMPtr.h" -#include "nsWidgetsCID.h" -#include "nsAppShell.h" - -#include "nsWindow.h" -#include "nsLookAndFeel.h" -#include "nsAppShellSingleton.h" -#include "nsScreenManagerGonk.h" -#include "nsIdleServiceGonk.h" -#include "nsTransferable.h" -#include "nsClipboard.h" -#include "nsClipboardHelper.h" - -#include "nsHTMLFormatConverter.h" -#include "nsXULAppAPI.h" - -#include "PuppetWidget.h" - -using namespace mozilla::widget; - -// taken from android/nsWidgetFactory.cpp. GfxInfo is a legacy kludge, unfortunately -// for the time being we still have to implement it on all platforms. -#include "GfxInfo.h" -namespace mozilla { -namespace widget { -// This constructor should really be shared with all platforms. -NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init) -} -} - -NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsScreenManagerGonk, nsScreenManagerGonk::GetInstance) -NS_GENERIC_FACTORY_CONSTRUCTOR(PuppetScreenManager) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIdleServiceGonk, nsIdleServiceGonk::GetInstance) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper) - -NS_DEFINE_NAMED_CID(NS_APPSHELL_CID); -NS_DEFINE_NAMED_CID(NS_WINDOW_CID); -NS_DEFINE_NAMED_CID(NS_CHILD_CID); -NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID); -NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID); -NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID); -NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID); -NS_DEFINE_NAMED_CID(NS_GFXINFO_CID); -NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID); -NS_DEFINE_NAMED_CID(NS_CLIPBOARDHELPER_CID); - -static nsresult -ScreenManagerConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) -{ - return (XRE_IsParentProcess()) ? - nsScreenManagerGonkConstructor(aOuter, aIID, aResult) : - PuppetScreenManagerConstructor(aOuter, aIID, aResult); -} - -static const mozilla::Module::CIDEntry kWidgetCIDs[] = { - { &kNS_WINDOW_CID, false, nullptr, nsWindowConstructor }, - { &kNS_CHILD_CID, false, nullptr, nsWindowConstructor }, - { &kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor }, - { &kNS_SCREENMANAGER_CID, false, nullptr, ScreenManagerConstructor }, - { &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor }, - { &kNS_IDLE_SERVICE_CID, false, nullptr, nsIdleServiceGonkConstructor }, - { &kNS_TRANSFERABLE_CID, false, nullptr, nsTransferableConstructor }, - { &kNS_GFXINFO_CID, false, nullptr, mozilla::widget::GfxInfoConstructor }, - { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardConstructor }, - { &kNS_CLIPBOARDHELPER_CID, false, nullptr, nsClipboardHelperConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { - { "@mozilla.org/widgets/window/gonk;1", &kNS_WINDOW_CID }, - { "@mozilla.org/widgets/child_window/gonk;1", &kNS_CHILD_CID }, - { "@mozilla.org/widget/appshell/gonk;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, - { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, - { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID }, - { "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID }, - { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID }, - { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID }, - { "@mozilla.org/widget/clipboardhelper;1", &kNS_CLIPBOARDHELPER_CID }, - { nullptr } -}; - -static void -nsWidgetGonkModuleDtor() -{ - // Shutdown all XP level widget classes. - WidgetUtils::Shutdown(); - - nsLookAndFeel::Shutdown(); - nsAppShellShutdown(); -} - -static const mozilla::Module kWidgetModule = { - mozilla::Module::kVersion, - kWidgetCIDs, - kWidgetContracts, - nullptr, - nullptr, - nsAppShellInit, - nsWidgetGonkModuleDtor -}; - -NSMODULE_DEFN(nsWidgetGonkModule) = &kWidgetModule; diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp deleted file mode 100644 index e11b7f233..000000000 --- a/widget/gonk/nsWindow.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsWindow.h" - -#include "mozilla/DebugOnly.h" - -#include <fcntl.h> - -#include "android/log.h" -#include "mozilla/dom/TabParent.h" -#include "mozilla/Preferences.h" -#include "mozilla/RefPtr.h" -#include "mozilla/Services.h" -#include "mozilla/FileUtils.h" -#include "mozilla/ClearOnShutdown.h" -#include "gfxContext.h" -#include "gfxPlatform.h" -#include "GLContextProvider.h" -#include "GLContext.h" -#include "GLContextEGL.h" -#include "nsAppShell.h" -#include "nsScreenManagerGonk.h" -#include "nsTArray.h" -#include "nsIWidgetListener.h" -#include "ClientLayerManager.h" -#include "BasicLayers.h" -#include "libdisplay/GonkDisplay.h" -#include "mozilla/TextEvents.h" -#include "mozilla/gfx/2D.h" -#include "mozilla/gfx/Logging.h" -#include "mozilla/layers/APZCTreeManager.h" -#include "mozilla/layers/APZThreadUtils.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/CompositorThread.h" -#include "mozilla/layers/CompositorSession.h" -#include "mozilla/TouchEvents.h" -#include "HwcComposer2D.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args) - -#define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) - -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::hal; -using namespace mozilla::gfx; -using namespace mozilla::gl; -using namespace mozilla::layers; -using namespace mozilla::widget; - -static nsWindow *gFocusedWindow = nullptr; - -NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget) - -nsWindow::nsWindow() -{ - RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->Initialize(); - - // This is a hack to force initialization of the compositor - // resources, if we're going to use omtc. - // - // NB: GetPlatform() will create the gfxPlatform, which wants - // to know the color depth, which asks our native window. - // This has to happen after other init has finished. - gfxPlatform::GetPlatform(); - if (!ShouldUseOffMainThreadCompositing()) { - MOZ_CRASH("How can we render apps, then?"); - } -} - -nsWindow::~nsWindow() -{ - if (mScreen->IsPrimaryScreen()) { - mComposer2D->SetCompositorBridgeParent(nullptr); - } -} - -void -nsWindow::DoDraw(void) -{ - if (!hal::GetScreenEnabled()) { - gDrawRequest = true; - return; - } - - RefPtr<nsScreenGonk> screen = nsScreenManagerGonk::GetPrimaryScreen(); - const nsTArray<nsWindow*>& windows = screen->GetTopWindows(); - - if (windows.IsEmpty()) { - LOG(" no window to draw, bailing"); - return; - } - - RefPtr<nsWindow> targetWindow = (nsWindow *)windows[0]; - while (targetWindow->GetLastChild()) { - targetWindow = (nsWindow *)targetWindow->GetLastChild(); - } - - nsIWidgetListener* listener = targetWindow->GetWidgetListener(); - if (listener) { - listener->WillPaintWindow(targetWindow); - } - - listener = targetWindow->GetWidgetListener(); - if (listener) { - LayerManager* lm = targetWindow->GetLayerManager(); - if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) { - // No need to do anything, the compositor will handle drawing - } else { - NS_RUNTIMEABORT("Unexpected layer manager type"); - } - - listener->DidPaintWindow(); - } -} - -void -nsWindow::ConfigureAPZControllerThread() -{ - APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop()); -} - -/*static*/ nsEventStatus -nsWindow::DispatchKeyInput(WidgetKeyboardEvent& aEvent) -{ - if (!gFocusedWindow) { - return nsEventStatus_eIgnore; - } - - gFocusedWindow->UserActivity(); - - nsEventStatus status; - aEvent.mWidget = gFocusedWindow; - gFocusedWindow->DispatchEvent(&aEvent, status); - return status; -} - -/*static*/ void -nsWindow::DispatchTouchInput(MultiTouchInput& aInput) -{ - APZThreadUtils::AssertOnControllerThread(); - - if (!gFocusedWindow) { - return; - } - - gFocusedWindow->DispatchTouchInputViaAPZ(aInput); -} - -class DispatchTouchInputOnMainThread : public mozilla::Runnable -{ -public: - DispatchTouchInputOnMainThread(const MultiTouchInput& aInput, - const ScrollableLayerGuid& aGuid, - const uint64_t& aInputBlockId, - nsEventStatus aApzResponse) - : mInput(aInput) - , mGuid(aGuid) - , mInputBlockId(aInputBlockId) - , mApzResponse(aApzResponse) - {} - - NS_IMETHOD Run() override { - if (gFocusedWindow) { - gFocusedWindow->DispatchTouchEventForAPZ(mInput, mGuid, mInputBlockId, mApzResponse); - } - return NS_OK; - } - -private: - MultiTouchInput mInput; - ScrollableLayerGuid mGuid; - uint64_t mInputBlockId; - nsEventStatus mApzResponse; -}; - -void -nsWindow::DispatchTouchInputViaAPZ(MultiTouchInput& aInput) -{ - APZThreadUtils::AssertOnControllerThread(); - - if (!mAPZC) { - // In general mAPZC should not be null, but during initial setup - // it might be, so we handle that case by ignoring touch input there. - return; - } - - // First send it through the APZ code - mozilla::layers::ScrollableLayerGuid guid; - uint64_t inputBlockId; - nsEventStatus result = mAPZC->ReceiveInputEvent(aInput, &guid, &inputBlockId); - // If the APZ says to drop it, then we drop it - if (result == nsEventStatus_eConsumeNoDefault) { - return; - } - - // Can't use NS_NewRunnableMethod because it only takes up to one arg and - // we need more. Also we can't pass in |this| to the task because nsWindow - // refcounting is not threadsafe. Instead we just use the gFocusedWindow - // static ptr inside the task. - NS_DispatchToMainThread(new DispatchTouchInputOnMainThread( - aInput, guid, inputBlockId, result)); -} - -void -nsWindow::DispatchTouchEventForAPZ(const MultiTouchInput& aInput, - const ScrollableLayerGuid& aGuid, - const uint64_t aInputBlockId, - nsEventStatus aApzResponse) -{ - MOZ_ASSERT(NS_IsMainThread()); - UserActivity(); - - // Convert it to an event we can send to Gecko - WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this); - - // Dispatch the event into the gecko root process for "normal" flow. - // The event might get sent to a child process, - // but if it doesn't we need to notify the APZ of various things. - // All of that happens in ProcessUntransformedAPZEvent - ProcessUntransformedAPZEvent(&event, aGuid, aInputBlockId, aApzResponse); -} - -class DispatchTouchInputOnControllerThread : public Runnable -{ -public: - DispatchTouchInputOnControllerThread(const MultiTouchInput& aInput) - : mInput(aInput) - {} - - NS_IMETHOD Run() override { - if (gFocusedWindow) { - gFocusedWindow->DispatchTouchInputViaAPZ(mInput); - } - return NS_OK; - } - -private: - MultiTouchInput mInput; -}; - -nsresult -nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId, - TouchPointerState aPointerState, - LayoutDeviceIntPoint aPoint, - double aPointerPressure, - uint32_t aPointerOrientation, - nsIObserver* aObserver) -{ - AutoObserverNotifier notifier(aObserver, "touchpoint"); - - if (aPointerState == TOUCH_HOVER) { - return NS_ERROR_UNEXPECTED; - } - - if (!mSynthesizedTouchInput) { - mSynthesizedTouchInput = MakeUnique<MultiTouchInput>(); - } - - // We should probably use a real timestamp here, but this is B2G and - // so this probably never even exercised any more. - uint32_t time = 0; - TimeStamp timestamp = TimeStamp::FromSystemTime(time); - - MultiTouchInput inputToDispatch = UpdateSynthesizedTouchState( - mSynthesizedTouchInput.get(), time, timestamp, aPointerId, aPointerState, - aPoint, aPointerPressure, aPointerOrientation); - - // Can't use NewRunnableMethod here because that will pass a const-ref - // argument to DispatchTouchInputViaAPZ whereas that function takes a - // non-const ref. At this callsite we don't care about the mutations that - // the function performs so this is fine. Also we can't pass |this| to the - // task because nsWindow refcounting is not threadsafe. Instead we just use - // the gFocusedWindow static ptr instead the task. - APZThreadUtils::RunOnControllerThread( - MakeAndAddRef<DispatchTouchInputOnControllerThread>(inputToDispatch)); - - return NS_OK; -} - -nsresult -nsWindow::Create(nsIWidget* aParent, - void* aNativeParent, - const LayoutDeviceIntRect& aRect, - nsWidgetInitData* aInitData) -{ - BaseCreate(aParent, aInitData); - - nsCOMPtr<nsIScreen> screen; - - uint32_t screenId = aParent ? ((nsWindow*)aParent)->mScreen->GetId() : - aInitData->mScreenId; - - RefPtr<nsScreenManagerGonk> screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->ScreenForId(screenId, getter_AddRefs(screen)); - - mScreen = static_cast<nsScreenGonk*>(screen.get()); - - mBounds = aRect; - - mParent = (nsWindow *)aParent; - mVisible = false; - - if (!aParent) { - mBounds = mScreen->GetRect(); - } - - mComposer2D = HwcComposer2D::GetInstance(); - - if (!IS_TOPLEVEL()) { - return NS_OK; - } - - mScreen->RegisterWindow(this); - - Resize(0, 0, mBounds.width, mBounds.height, false); - - return NS_OK; -} - -void -nsWindow::Destroy() -{ - mOnDestroyCalled = true; - mScreen->UnregisterWindow(this); - if (this == gFocusedWindow) { - gFocusedWindow = nullptr; - } - nsBaseWidget::OnDestroy(); -} - -NS_IMETHODIMP -nsWindow::Show(bool aState) -{ - if (mWindowType == eWindowType_invisible) { - return NS_OK; - } - - if (mVisible == aState) { - return NS_OK; - } - - mVisible = aState; - if (!IS_TOPLEVEL()) { - return mParent ? mParent->Show(aState) : NS_OK; - } - - if (aState) { - BringToTop(); - } else { - const nsTArray<nsWindow*>& windows = - mScreen->GetTopWindows(); - for (unsigned int i = 0; i < windows.Length(); i++) { - nsWindow *win = windows[i]; - if (!win->mVisible) { - continue; - } - win->BringToTop(); - break; - } - } - - return NS_OK; -} - -bool -nsWindow::IsVisible() const -{ - return mVisible; -} - -NS_IMETHODIMP -nsWindow::Move(double aX, - double aY) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::Resize(double aWidth, - double aHeight, - bool aRepaint) -{ - return Resize(0, 0, aWidth, aHeight, aRepaint); -} - -NS_IMETHODIMP -nsWindow::Resize(double aX, - double aY, - double aWidth, - double aHeight, - bool aRepaint) -{ - mBounds = LayoutDeviceIntRect(NSToIntRound(aX), NSToIntRound(aY), - NSToIntRound(aWidth), NSToIntRound(aHeight)); - if (mWidgetListener) { - mWidgetListener->WindowResized(this, mBounds.width, mBounds.height); - } - - if (aRepaint) { - Invalidate(mBounds); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::Enable(bool aState) -{ - return NS_OK; -} - -bool -nsWindow::IsEnabled() const -{ - return true; -} - -NS_IMETHODIMP -nsWindow::SetFocus(bool aRaise) -{ - if (aRaise) { - BringToTop(); - } - - if (!IS_TOPLEVEL() && mScreen->IsPrimaryScreen()) { - // We should only set focused window on non-toplevel primary window. - gFocusedWindow = this; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>&) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) -{ - nsWindow *top = mParent; - while (top && top->mParent) { - top = top->mParent; - } - const nsTArray<nsWindow*>& windows = mScreen->GetTopWindows(); - if (top != windows[0] && this != windows[0]) { - return NS_OK; - } - - gDrawRequest = true; - mozilla::NotifyEvent(); - return NS_OK; -} - -LayoutDeviceIntPoint -nsWindow::WidgetToScreenOffset() -{ - LayoutDeviceIntPoint p(0, 0); - nsWindow *w = this; - - while (w && w->mParent) { - p.x += w->mBounds.x; - p.y += w->mBounds.y; - - w = w->mParent; - } - - return p; -} - -void* -nsWindow::GetNativeData(uint32_t aDataType) -{ - switch (aDataType) { - case NS_NATIVE_WINDOW: - // Called before primary display's EGLSurface creation. - return mScreen->GetNativeWindow(); - case NS_NATIVE_OPENGL_CONTEXT: - return mScreen->GetGLContext().take(); - case NS_RAW_NATIVE_IME_CONTEXT: { - void* pseudoIMEContext = GetPseudoIMEContext(); - if (pseudoIMEContext) { - return pseudoIMEContext; - } - // There is only one IME context on Gonk. - return NS_ONLY_ONE_NATIVE_IME_CONTEXT; - } - } - - return nullptr; -} - -void -nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal) -{ - switch (aDataType) { - case NS_NATIVE_OPENGL_CONTEXT: - GLContext* context = reinterpret_cast<GLContext*>(aVal); - if (!context) { - mScreen->SetEGLInfo(EGL_NO_DISPLAY, - EGL_NO_SURFACE, - nullptr); - return; - } - mScreen->SetEGLInfo(GLContextEGL::Cast(context)->GetEGLDisplay(), - GLContextEGL::Cast(context)->GetEGLSurface(), - context); - return; - } -} - -NS_IMETHODIMP -nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) -{ - if (mWidgetListener) { - aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents); - } - return NS_OK; -} - -NS_IMETHODIMP_(void) -nsWindow::SetInputContext(const InputContext& aContext, - const InputContextAction& aAction) -{ - mInputContext = aContext; -} - -NS_IMETHODIMP_(InputContext) -nsWindow::GetInputContext() -{ - return mInputContext; -} - -nsresult -nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*) -{ - if (mWindowType != eWindowType_toplevel) { - // Ignore fullscreen request for non-toplevel windows. - NS_WARNING("MakeFullScreen() on a dialog or child widget?"); - nsBaseWidget::InfallibleMakeFullScreen(aFullScreen); - return NS_OK; - } - - if (aFullScreen) { - // Fullscreen is "sticky" for toplevel widgets on gonk: we - // must paint the entire screen, and should only have one - // toplevel widget, so it doesn't make sense to ever "exit" - // fullscreen. If we do, we can leave parts of the screen - // unpainted. - nsIntRect virtualBounds; - mScreen->GetRect(&virtualBounds.x, &virtualBounds.y, - &virtualBounds.width, &virtualBounds.height); - Resize(virtualBounds.x, virtualBounds.y, - virtualBounds.width, virtualBounds.height, - /*repaint*/true); - } - - if (nsIWidgetListener* listener = GetWidgetListener()) { - listener->FullscreenChanged(aFullScreen); - } - return NS_OK; -} - -already_AddRefed<DrawTarget> -nsWindow::StartRemoteDrawing() -{ - RefPtr<DrawTarget> buffer = mScreen->StartRemoteDrawing(); - return buffer.forget(); -} - -void -nsWindow::EndRemoteDrawing() -{ - mScreen->EndRemoteDrawing(); -} - -float -nsWindow::GetDPI() -{ - return mScreen->GetDpi(); -} - -double -nsWindow::GetDefaultScaleInternal() -{ - float dpi = GetDPI(); - // The mean pixel density for mdpi devices is 160dpi, 240dpi for hdpi, - // and 320dpi for xhdpi, respectively. - // We'll take the mid-value between these three numbers as the boundary. - if (dpi < 200.0) { - return 1.0; // mdpi devices. - } - if (dpi < 280.0) { - return 1.5; // hdpi devices. - } - // xhdpi devices and beyond. - return floor(dpi / 150.0 + 0.5); -} - -LayerManager * -nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, - LayersBackend aBackendHint, - LayerManagerPersistence aPersistence) -{ - if (mLayerManager) { - // This layer manager might be used for painting outside of DoDraw(), so we need - // to set the correct rotation on it. - if (ClientLayerManager* manager = mLayerManager->AsClientLayerManager()) { - uint32_t rotation = mScreen->EffectiveScreenRotation(); - manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, - ScreenRotation(rotation)); - } - return mLayerManager; - } - - const nsTArray<nsWindow*>& windows = mScreen->GetTopWindows(); - nsWindow *topWindow = windows[0]; - - if (!topWindow) { - LOGW(" -- no topwindow\n"); - return nullptr; - } - - CreateCompositor(); - if (RefPtr<CompositorBridgeParent> bridge = GetCompositorBridgeParent()) { - mScreen->SetCompositorBridgeParent(bridge); - if (mScreen->IsPrimaryScreen()) { - mComposer2D->SetCompositorBridgeParent(bridge); - } - } - MOZ_ASSERT(mLayerManager); - return mLayerManager; -} - -void -nsWindow::DestroyCompositor() -{ - if (RefPtr<CompositorBridgeParent> bridge = GetCompositorBridgeParent()) { - mScreen->SetCompositorBridgeParent(nullptr); - if (mScreen->IsPrimaryScreen()) { - // Unset CompositorBridgeParent - mComposer2D->SetCompositorBridgeParent(nullptr); - } - } - nsBaseWidget::DestroyCompositor(); -} - -void -nsWindow::BringToTop() -{ - const nsTArray<nsWindow*>& windows = mScreen->GetTopWindows(); - if (!windows.IsEmpty()) { - if (nsIWidgetListener* listener = windows[0]->GetWidgetListener()) { - listener->WindowDeactivated(); - } - } - - mScreen->BringToTop(this); - - if (mWidgetListener) { - mWidgetListener->WindowActivated(); - } - - Invalidate(mBounds); -} - -void -nsWindow::UserActivity() -{ - if (!mIdleService) { - mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); - } - - if (mIdleService) { - mIdleService->ResetIdleTimeOut(0); - } -} - -uint32_t -nsWindow::GetGLFrameBufferFormat() -{ - if (mLayerManager && - mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { - // We directly map the hardware fb on Gonk. The hardware fb - // has RGB format. - return LOCAL_GL_RGB; - } - return LOCAL_GL_NONE; -} - -LayoutDeviceIntRect -nsWindow::GetNaturalBounds() -{ - return mScreen->GetNaturalBounds(); -} - -nsScreenGonk* -nsWindow::GetScreen() -{ - return mScreen; -} - -bool -nsWindow::NeedsPaint() -{ - if (!mLayerManager) { - return false; - } - return nsIWidget::NeedsPaint(); -} - -Composer2D* -nsWindow::GetComposer2D() -{ - if (mScreen->GetDisplayType() == GonkDisplay::DISPLAY_VIRTUAL) { - return nullptr; - } - - return mComposer2D; -} - -CompositorBridgeParent* -nsWindow::GetCompositorBridgeParent() const -{ - return mCompositorSession ? mCompositorSession->GetInProcessBridge() : nullptr; -} diff --git a/widget/gonk/nsWindow.h b/widget/gonk/nsWindow.h deleted file mode 100644 index 6106982f9..000000000 --- a/widget/gonk/nsWindow.h +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsWindow_h -#define nsWindow_h - -#include "InputData.h" -#include "mozilla/UniquePtr.h" -#include "nsBaseWidget.h" -#include "nsRegion.h" -#include "nsIIdleServiceInternal.h" -#include "Units.h" - -class ANativeWindowBuffer; - -namespace widget { -struct InputContext; -struct InputContextAction; -} - -namespace mozilla { -class HwcComposer2D; -} - -class nsScreenGonk; - -class nsWindow : public nsBaseWidget -{ -public: - nsWindow(); - - NS_DECL_ISUPPORTS_INHERITED - - static void DoDraw(void); - static nsEventStatus DispatchKeyInput(mozilla::WidgetKeyboardEvent& aEvent); - static void DispatchTouchInput(mozilla::MultiTouchInput& aInput); - - using nsBaseWidget::Create; // for Create signature not overridden here - virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent, - void* aNativeParent, - const LayoutDeviceIntRect& aRect, - nsWidgetInitData* aInitData) override; - virtual void Destroy(); - - NS_IMETHOD Show(bool aState); - virtual bool IsVisible() const; - NS_IMETHOD Move(double aX, - double aY); - NS_IMETHOD Resize(double aWidth, - double aHeight, - bool aRepaint); - NS_IMETHOD Resize(double aX, - double aY, - double aWidth, - double aHeight, - bool aRepaint); - NS_IMETHOD Enable(bool aState); - virtual bool IsEnabled() const; - NS_IMETHOD SetFocus(bool aRaise = false); - NS_IMETHOD ConfigureChildren(const nsTArray<nsIWidget::Configuration>&); - NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect); - virtual void* GetNativeData(uint32_t aDataType); - virtual void SetNativeData(uint32_t aDataType, uintptr_t aVal); - NS_IMETHOD SetTitle(const nsAString& aTitle) - { - return NS_OK; - } - virtual LayoutDeviceIntPoint WidgetToScreenOffset(); - void DispatchTouchInputViaAPZ(mozilla::MultiTouchInput& aInput); - void DispatchTouchEventForAPZ(const mozilla::MultiTouchInput& aInput, - const ScrollableLayerGuid& aGuid, - const uint64_t aInputBlockId, - nsEventStatus aApzResponse); - NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent, - nsEventStatus& aStatus); - virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId, - TouchPointerState aPointerState, - LayoutDeviceIntPoint aPoint, - double aPointerPressure, - uint32_t aPointerOrientation, - nsIObserver* aObserver) override; - - virtual nsresult MakeFullScreen( - bool aFullScreen, nsIScreen* aTargetScreen = nullptr) override; - - virtual already_AddRefed<mozilla::gfx::DrawTarget> - StartRemoteDrawing() override; - virtual void EndRemoteDrawing() override; - - virtual float GetDPI(); - virtual double GetDefaultScaleInternal(); - virtual mozilla::layers::LayerManager* - GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr, - LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE, - LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT); - virtual void DestroyCompositor(); - - NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, - const InputContextAction& aAction); - NS_IMETHOD_(InputContext) GetInputContext(); - - virtual uint32_t GetGLFrameBufferFormat() override; - - virtual LayoutDeviceIntRect GetNaturalBounds() override; - virtual bool NeedsPaint(); - - virtual Composer2D* GetComposer2D() override; - - void ConfigureAPZControllerThread() override; - - nsScreenGonk* GetScreen(); - -protected: - nsWindow* mParent; - bool mVisible; - InputContext mInputContext; - nsCOMPtr<nsIIdleServiceInternal> mIdleService; - - virtual ~nsWindow(); - - void BringToTop(); - - // Call this function when the users activity is the direct cause of an - // event (like a keypress or mouse click). - void UserActivity(); - - bool UseExternalCompositingSurface() const override { - return true; - } - CompositorBridgeParent* GetCompositorBridgeParent() const; - -private: - // This is used by SynthesizeNativeTouchPoint to maintain state between - // multiple synthesized points - mozilla::UniquePtr<mozilla::MultiTouchInput> mSynthesizedTouchInput; - - RefPtr<nsScreenGonk> mScreen; - - RefPtr<mozilla::HwcComposer2D> mComposer2D; -}; - -#endif /* nsWindow_h */ |