Merge "jpegrecoverymap: Return ICCProfile data from JPEG/R file"
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 62c3ae1..da97c3e 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -51,33 +51,24 @@
static const size_t MAX_DEGREE = 4;
// Estimator time base.
- nsecs_t time;
+ nsecs_t time = 0;
// Polynomial coefficients describing motion.
- float coeff[MAX_DEGREE + 1];
+ std::array<float, MAX_DEGREE + 1> coeff{};
// Polynomial degree (number of coefficients), or zero if no information is
// available.
- uint32_t degree;
+ uint32_t degree = 0;
// 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++) {
- coeff[i] = 0;
- }
- }
+ float confidence = 0;
};
/*
* Contains all available velocity data from a VelocityTracker.
*/
struct ComputedVelocity {
- inline std::optional<float> getVelocity(int32_t axis, uint32_t id) const {
+ inline std::optional<float> getVelocity(int32_t axis, int32_t id) const {
const auto& axisVelocities = mVelocities.find(axis);
if (axisVelocities == mVelocities.end()) {
return {};
@@ -91,7 +82,7 @@
return axisIdVelocity->second;
}
- inline void addVelocity(int32_t axis, uint32_t id, float velocity) {
+ inline void addVelocity(int32_t axis, int32_t id, float velocity) {
mVelocities[axis][id] = velocity;
}
@@ -112,19 +103,13 @@
// Resets the velocity tracker state.
void clear();
- // Resets the velocity tracker state for specific pointers.
+ // Resets the velocity tracker state for a specific pointer.
// 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);
+ void clearPointer(int32_t pointerId);
- // Adds movement information for a set of pointers.
- // The idBits bitfield specifies the pointer ids of the pointers whose data points
- // are included in the movement.
- // The positions map contains a mapping of an axis to positions array.
- // The positions arrays contain information for each pointer in order by increasing id.
- // Each array's size should be equal to the number of one bits in idBits.
- void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::map<int32_t, std::vector<float>>& positions);
+ // Adds movement information for a pointer for a specific axis
+ void addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis, float position);
// Adds movement information for all pointers in a MotionEvent, including historical samples.
void addMovement(const MotionEvent* event);
@@ -132,7 +117,7 @@
// Returns the velocity of the specified pointer id and axis in position units per second.
// Returns empty optional if there is insufficient movement information for the pointer, or if
// the given axis is not supported for velocity tracking.
- std::optional<float> getVelocity(int32_t axis, uint32_t id) const;
+ std::optional<float> getVelocity(int32_t axis, int32_t pointerId) const;
// Returns a ComputedVelocity instance with all available velocity data, using the given units
// (reference: units == 1 means "per millisecond"), and clamping each velocity between
@@ -142,15 +127,15 @@
// Gets an estimator for the recent movements of the specified pointer id for the given axis.
// Returns false and clears the estimator if there is no information available
// about the pointer.
- bool getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const;
+ std::optional<Estimator> getEstimator(int32_t axis, int32_t pointerId) const;
// Gets the active pointer id, or -1 if none.
- inline int32_t getActivePointerId() const { return mActivePointerId; }
+ inline int32_t getActivePointerId() const { return mActivePointerId.value_or(-1); }
private:
nsecs_t mLastEventTime;
BitSet32 mCurrentPointerIdBits;
- int32_t mActivePointerId;
+ std::optional<int32_t> mActivePointerId;
// An override strategy passed in the constructor to be used for all axes.
// This strategy will apply to all axes, unless the default strategy is specified here.
@@ -182,10 +167,9 @@
public:
virtual ~VelocityTrackerStrategy() { }
- virtual void clearPointers(BitSet32 idBits) = 0;
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) = 0;
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
+ virtual void clearPointer(int32_t pointerId) = 0;
+ virtual void addMovement(nsecs_t eventTime, int32_t pointerId, float position) = 0;
+ virtual std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const = 0;
};
@@ -194,29 +178,28 @@
*/
class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy {
public:
- enum Weighting {
+ enum class Weighting {
// No weights applied. All data points are equally reliable.
- WEIGHTING_NONE,
+ NONE,
// Weight by time delta. Data points clustered together are weighted less.
- WEIGHTING_DELTA,
+ DELTA,
// Weight such that points within a certain horizon are weighed more than those
// outside of that horizon.
- WEIGHTING_CENTRAL,
+ CENTRAL,
// Weight such that points older than a certain amount are weighed less.
- WEIGHTING_RECENT,
+ RECENT,
};
// Degree must be no greater than Estimator::MAX_DEGREE.
- LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE);
- virtual ~LeastSquaresVelocityTrackerStrategy();
+ LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = Weighting::NONE);
+ ~LeastSquaresVelocityTrackerStrategy() override;
- virtual void clearPointers(BitSet32 idBits);
- void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+ void clearPointer(int32_t pointerId) override;
+ void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override;
+ std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override;
private:
// Sample horizon.
@@ -229,18 +212,15 @@
struct Movement {
nsecs_t eventTime;
- BitSet32 idBits;
- float positions[MAX_POINTERS];
-
- inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
+ float position;
};
- float chooseWeight(uint32_t index) const;
+ float chooseWeight(int32_t pointerId, uint32_t index) const;
const uint32_t mDegree;
const Weighting mWeighting;
- uint32_t mIndex;
- Movement mMovements[HISTORY_SIZE];
+ std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex;
+ std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements;
};
@@ -251,12 +231,11 @@
public:
// Degree must be 1 or 2.
IntegratingVelocityTrackerStrategy(uint32_t degree);
- ~IntegratingVelocityTrackerStrategy();
+ ~IntegratingVelocityTrackerStrategy() override;
- virtual void clearPointers(BitSet32 idBits);
- void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+ void clearPointer(int32_t pointerId) override;
+ void addMovement(nsecs_t eventTime, int32_t pointerId, float positions) override;
+ std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override;
private:
// Current state estimate for a particular pointer.
@@ -283,12 +262,11 @@
class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy {
public:
LegacyVelocityTrackerStrategy();
- virtual ~LegacyVelocityTrackerStrategy();
+ ~LegacyVelocityTrackerStrategy() override;
- virtual void clearPointers(BitSet32 idBits);
- void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+ void clearPointer(int32_t pointerId) override;
+ void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override;
+ std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override;
private:
// Oldest sample to consider when calculating the velocity.
@@ -302,25 +280,21 @@
struct Movement {
nsecs_t eventTime;
- BitSet32 idBits;
- float positions[MAX_POINTERS];
-
- inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
+ float position;
};
- uint32_t mIndex;
- Movement mMovements[HISTORY_SIZE];
+ std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex;
+ std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements;
};
class ImpulseVelocityTrackerStrategy : public VelocityTrackerStrategy {
public:
ImpulseVelocityTrackerStrategy(bool deltaValues);
- virtual ~ImpulseVelocityTrackerStrategy();
+ ~ImpulseVelocityTrackerStrategy() override;
- virtual void clearPointers(BitSet32 idBits);
- void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
- virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
+ void clearPointer(int32_t pointerId) override;
+ void addMovement(nsecs_t eventTime, int32_t pointerId, float position) override;
+ std::optional<VelocityTracker::Estimator> getEstimator(int32_t pointerId) const override;
private:
// Sample horizon.
@@ -333,10 +307,7 @@
struct Movement {
nsecs_t eventTime;
- BitSet32 idBits;
- float positions[MAX_POINTERS];
-
- inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
+ float position;
};
// Whether or not the input movement values for the strategy come in the form of delta values.
@@ -344,8 +315,8 @@
// velocity calculation.
const bool mDeltaValues;
- size_t mIndex;
- Movement mMovements[HISTORY_SIZE];
+ std::map<int32_t /*pointerId*/, size_t /*positionInArray*/> mIndex;
+ std::map<int32_t /*pointerId*/, std::array<Movement, HISTORY_SIZE>> mMovements;
};
} // namespace android
diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h
index 8cc8105..dc572ac 100644
--- a/libs/binder/include/binder/IInterface.h
+++ b/libs/binder/include/binder/IInterface.h
@@ -230,6 +230,7 @@
"android.graphicsenv.IGpuService",
"android.gui.IConsumerListener",
"android.gui.IGraphicBufferConsumer",
+ "android.gui.ITransactionComposerListener",
"android.gui.SensorEventConnection",
"android.gui.SensorServer",
"android.hardware.ICamera",
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index a0e75ff..a77ca04 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -42,7 +42,6 @@
namespace android {
-using gui::CallbackId;
using gui::DisplayCaptureArgs;
using gui::IDisplayEventConnection;
using gui::IRegionSamplingListener;
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 23d7d50..2b25b61 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -21,11 +21,22 @@
#include <optional>
#include <gui/ISurfaceComposer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
-#include <gui/ListenerStats.h>
#include <private/gui/ParcelUtils.h>
-namespace android::gui {
+namespace android {
+
+namespace { // Anonymous
+
+enum class Tag : uint32_t {
+ ON_TRANSACTION_COMPLETED = IBinder::FIRST_CALL_TRANSACTION,
+ ON_RELEASE_BUFFER,
+ ON_TRANSACTION_QUEUE_STALLED,
+ LAST = ON_TRANSACTION_QUEUE_STALLED,
+};
+
+} // Anonymous namespace
status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const {
status_t err = output->writeUint64(frameNumber);
@@ -263,6 +274,60 @@
return listenerStats;
}
+class BpTransactionCompletedListener : public SafeBpInterface<ITransactionCompletedListener> {
+public:
+ explicit BpTransactionCompletedListener(const sp<IBinder>& impl)
+ : SafeBpInterface<ITransactionCompletedListener>(impl, "BpTransactionCompletedListener") {
+ }
+
+ ~BpTransactionCompletedListener() override;
+
+ void onTransactionCompleted(ListenerStats stats) override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::
+ onTransactionCompleted)>(Tag::ON_TRANSACTION_COMPLETED,
+ stats);
+ }
+
+ void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
+ uint32_t currentMaxAcquiredBufferCount) override {
+ callRemoteAsync<decltype(&ITransactionCompletedListener::
+ onReleaseBuffer)>(Tag::ON_RELEASE_BUFFER, callbackId,
+ releaseFence,
+ currentMaxAcquiredBufferCount);
+ }
+
+ void onTransactionQueueStalled(const String8& reason) override {
+ callRemoteAsync<
+ decltype(&ITransactionCompletedListener::
+ onTransactionQueueStalled)>(Tag::ON_TRANSACTION_QUEUE_STALLED,
+ reason);
+ }
+};
+
+// Out-of-line virtual method definitions to trigger vtable emission in this translation unit (see
+// clang warning -Wweak-vtables)
+BpTransactionCompletedListener::~BpTransactionCompletedListener() = default;
+
+IMPLEMENT_META_INTERFACE(TransactionCompletedListener, "android.gui.ITransactionComposerListener");
+
+status_t BnTransactionCompletedListener::onTransact(uint32_t code, const Parcel& data,
+ Parcel* reply, uint32_t flags) {
+ if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ auto tag = static_cast<Tag>(code);
+ switch (tag) {
+ case Tag::ON_TRANSACTION_COMPLETED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionCompleted);
+ case Tag::ON_RELEASE_BUFFER:
+ return callLocalAsync(data, reply, &ITransactionCompletedListener::onReleaseBuffer);
+ case Tag::ON_TRANSACTION_QUEUE_STALLED:
+ return callLocalAsync(data, reply,
+ &ITransactionCompletedListener::onTransactionQueueStalled);
+ }
+}
+
ListenerCallbacks ListenerCallbacks::filter(CallbackId::Type type) const {
std::vector<CallbackId> filteredCallbackIds;
for (const auto& callbackId : callbackIds) {
@@ -301,4 +366,4 @@
const ReleaseCallbackId ReleaseCallbackId::INVALID_ID = ReleaseCallbackId(0, 0);
-}; // namespace android::gui
+}; // namespace android
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 0d1a69b..59b62fe 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -51,7 +51,6 @@
namespace android {
-using gui::CallbackId;
using gui::FocusRequest;
using gui::WindowInfoHandle;
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index a2ed8aa..92125ea 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -314,8 +314,7 @@
}
}
-binder::Status TransactionCompletedListener::onTransactionCompleted(
- const ListenerStats& listenerStats) {
+void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
std::unordered_map<CallbackId, CallbackTranslation, CallbackIdHash> callbacksMap;
std::multimap<int32_t, sp<JankDataListener>> jankListenersMap;
{
@@ -455,10 +454,9 @@
}
}
}
- return binder::Status::ok();
}
-binder::Status TransactionCompletedListener::onTransactionQueueStalled(const std::string& reason) {
+void TransactionCompletedListener::onTransactionQueueStalled(const String8& reason) {
std::unordered_map<void*, std::function<void(const std::string&)>> callbackCopy;
{
std::scoped_lock<std::mutex> lock(mMutex);
@@ -467,7 +465,6 @@
for (auto const& it : callbackCopy) {
it.second(reason.c_str());
}
- return binder::Status::ok();
}
void TransactionCompletedListener::addQueueStallListener(
@@ -481,12 +478,9 @@
mQueueStallListeners.erase(id);
}
-binder::Status TransactionCompletedListener::onReleaseBuffer(
- const ReleaseCallbackId& callbackId,
- const std::optional<os::ParcelFileDescriptor>& releaseFenceFd,
- int32_t currentMaxAcquiredBufferCount) {
- sp<Fence> releaseFence(releaseFenceFd ? new Fence(::dup(releaseFenceFd->get()))
- : Fence::NO_FENCE);
+void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId,
+ sp<Fence> releaseFence,
+ uint32_t currentMaxAcquiredBufferCount) {
ReleaseBufferCallback callback;
{
std::scoped_lock<std::mutex> lock(mMutex);
@@ -495,14 +489,13 @@
if (!callback) {
ALOGE("Could not call release buffer callback, buffer not found %s",
callbackId.to_string().c_str());
- return binder::Status::fromExceptionCode(binder::Status::EX_ILLEGAL_ARGUMENT);
+ return;
}
std::optional<uint32_t> optionalMaxAcquiredBufferCount =
- static_cast<uint32_t>(currentMaxAcquiredBufferCount) == UINT_MAX
+ currentMaxAcquiredBufferCount == UINT_MAX
? std::nullopt
: std::make_optional<uint32_t>(currentMaxAcquiredBufferCount);
callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount);
- return binder::Status::ok();
}
ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked(
@@ -832,11 +825,7 @@
->mReleaseCallbackThread
.addReleaseCallback(state.bufferData->generateReleaseCallbackId(), fence);
} else {
- std::optional<os::ParcelFileDescriptor> fenceFd;
- if (fence != Fence::NO_FENCE) {
- fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(fence->get())));
- }
- listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fenceFd, UINT_MAX);
+ listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fence, UINT_MAX);
}
}
@@ -2496,6 +2485,20 @@
return statusTFromBinderStatus(status);
}
+status_t SurfaceComposerClient::getHdrConversionCapabilities(
+ std::vector<gui::HdrConversionCapability>* hdrConversionCapabilities) {
+ binder::Status status = ComposerServiceAIDL::getComposerService()->getHdrConversionCapabilities(
+ hdrConversionCapabilities);
+ return statusTFromBinderStatus(status);
+}
+
+status_t SurfaceComposerClient::setHdrConversionStrategy(
+ gui::HdrConversionStrategy hdrConversionStrategy) {
+ binder::Status status = ComposerServiceAIDL::getComposerService()->setHdrConversionStrategy(
+ hdrConversionStrategy);
+ return statusTFromBinderStatus(status);
+}
+
status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) {
binder::Status status =
ComposerServiceAIDL::getComposerService()->setOverrideFrameRate(uid, frameRate);
@@ -2866,11 +2869,7 @@
while (!callbackInfos.empty()) {
auto [callbackId, releaseFence] = callbackInfos.front();
- std::optional<os::ParcelFileDescriptor> fenceFd;
- if (releaseFence != Fence::NO_FENCE) {
- fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(releaseFence->get())));
- }
- listener->onReleaseBuffer(callbackId, fenceFd, UINT_MAX);
+ listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX);
callbackInfos.pop();
}
diff --git a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl b/libs/gui/aidl/android/gui/HdrConversionCapability.aidl
similarity index 75%
rename from libs/gui/aidl/android/gui/ReleaseCallbackId.aidl
rename to libs/gui/aidl/android/gui/HdrConversionCapability.aidl
index c86de34..1bcfd38 100644
--- a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl
+++ b/libs/gui/aidl/android/gui/HdrConversionCapability.aidl
@@ -16,4 +16,10 @@
package android.gui;
-parcelable ReleaseCallbackId cpp_header "gui/ReleaseCallbackId.h";
+// TODO(b/265277221): use android.hardware.graphics.common.HdrConversionCapability.aidl
+/** @hide */
+parcelable HdrConversionCapability {
+ int sourceType;
+ int outputType;
+ boolean addsLatency;
+}
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl b/libs/gui/aidl/android/gui/HdrConversionStrategy.aidl
similarity index 74%
copy from libs/gui/aidl/android/gui/ReleaseCallbackId.aidl
copy to libs/gui/aidl/android/gui/HdrConversionStrategy.aidl
index c86de34..1be74b4 100644
--- a/libs/gui/aidl/android/gui/ReleaseCallbackId.aidl
+++ b/libs/gui/aidl/android/gui/HdrConversionStrategy.aidl
@@ -16,4 +16,10 @@
package android.gui;
-parcelable ReleaseCallbackId cpp_header "gui/ReleaseCallbackId.h";
+// TODO(b/265277221): use android.hardware.graphics.common.HdrConversionStrategy.aidl
+/** @hide */
+union HdrConversionStrategy {
+ boolean passthrough = true;
+ int[] autoAllowedHdrTypes;
+ int forceHdrConversion;
+}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index a0b613c..c08a7c6 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -30,6 +30,8 @@
import android.gui.DynamicDisplayInfo;
import android.gui.FrameEvent;
import android.gui.FrameStats;
+import android.gui.HdrConversionCapability;
+import android.gui.HdrConversionStrategy;
import android.gui.IDisplayEventConnection;
import android.gui.IFpsListener;
import android.gui.IHdrLayerInfoListener;
@@ -162,6 +164,26 @@
boolean getBootDisplayModeSupport();
/**
+ * Gets the HDR conversion capabilities of the device. The conversion capability defines whether
+ * conversion from sourceType to outputType is possible (with or without latency).
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ List<HdrConversionCapability> getHdrConversionCapabilities();
+
+ /**
+ * Sets the HDR conversion strategy of the device.
+ *
+ * Requires the ACCESS_SURFACE_FLINGER permission.
+ */
+ void setHdrConversionStrategy(in HdrConversionStrategy hdrConversionStrategy);
+
+ /**
+ * Gets whether HDR output conversion operations are supported on the device.
+ */
+ boolean getHdrOutputConversionSupport();
+
+ /**
* Switches Auto Low Latency Mode on/off on the connected display, if it is
* available. This should only be called if the display supports Auto Low
* Latency Mode as reported in #getDynamicDisplayInfo.
diff --git a/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl b/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl
deleted file mode 100644
index dde4d38..0000000
--- a/libs/gui/aidl/android/gui/ITransactionCompletedListener.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-package android.gui;
-
-import android.gui.ListenerStats;
-import android.gui.ReleaseCallbackId;
-
-/** @hide */
-oneway interface ITransactionCompletedListener {
- void onTransactionCompleted(in ListenerStats stats);
-
- void onReleaseBuffer(in ReleaseCallbackId callbackId,
- in @nullable ParcelFileDescriptor releaseFenceFd,
- int currentMaxAcquiredBufferCount);
-
- void onTransactionQueueStalled(@utf8InCpp String name);
-}
diff --git a/libs/gui/aidl/android/gui/ListenerStats.aidl b/libs/gui/aidl/android/gui/ListenerStats.aidl
deleted file mode 100644
index 63248b2..0000000
--- a/libs/gui/aidl/android/gui/ListenerStats.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-package android.gui;
-
-parcelable ListenerStats cpp_header "gui/ListenerStats.h";
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 8810e4e..685bd92 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -91,6 +91,11 @@
MOCK_METHOD(binder::Status, setBootDisplayMode, (const sp<IBinder>&, int), (override));
MOCK_METHOD(binder::Status, clearBootDisplayMode, (const sp<IBinder>&), (override));
MOCK_METHOD(binder::Status, getBootDisplayModeSupport, (bool*), (override));
+ MOCK_METHOD(binder::Status, getHdrConversionCapabilities,
+ (std::vector<gui::HdrConversionCapability>*), (override));
+ MOCK_METHOD(binder::Status, setHdrConversionStrategy, (const gui::HdrConversionStrategy&),
+ (override));
+ MOCK_METHOD(binder::Status, getHdrOutputConversionSupport, (bool*), (override));
MOCK_METHOD(binder::Status, setAutoLowLatencyMode, (const sp<IBinder>&, bool), (override));
MOCK_METHOD(binder::Status, setGameContentType, (const sp<IBinder>&, bool), (override));
MOCK_METHOD(binder::Status, captureDisplay,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 06a246e..045cc2a 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -23,11 +23,11 @@
#include <android/gui/IHdrLayerInfoListener.h>
#include <android/gui/IRegionSamplingListener.h>
#include <android/gui/IScreenCaptureListener.h>
-#include <android/gui/ITransactionCompletedListener.h>
#include <android/gui/ITunnelModeEnabledListener.h>
#include <android/gui/IWindowInfosListener.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
+#include <gui/ITransactionCompletedListener.h>
#include <gui/SpHash.h>
#include <math/vec4.h>
#include <stdint.h>
@@ -66,7 +66,6 @@
using gui::IDisplayEventConnection;
using gui::IRegionSamplingListener;
using gui::IScreenCaptureListener;
-using gui::ListenerCallbacks;
using gui::SpHash;
namespace gui {
diff --git a/libs/gui/include/gui/ListenerStats.h b/libs/gui/include/gui/ITransactionCompletedListener.h
similarity index 81%
rename from libs/gui/include/gui/ListenerStats.h
rename to libs/gui/include/gui/ITransactionCompletedListener.h
index 3a12802..453e8f3 100644
--- a/libs/gui/include/gui/ListenerStats.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -24,8 +24,6 @@
#include <binder/SafeInterface.h>
#include <gui/FrameTimestamps.h>
-#include <gui/ReleaseCallbackId.h>
-
#include <ui/Fence.h>
#include <utils/Timers.h>
@@ -34,7 +32,10 @@
#include <unordered_set>
#include <variant>
-namespace android::gui {
+namespace android {
+
+class ITransactionCompletedListener;
+class ListenerCallbacks;
class CallbackId : public Parcelable {
public:
@@ -53,6 +54,30 @@
std::size_t operator()(const CallbackId& key) const { return std::hash<int64_t>()(key.id); }
};
+class ReleaseCallbackId : public Parcelable {
+public:
+ static const ReleaseCallbackId INVALID_ID;
+
+ uint64_t bufferId;
+ uint64_t framenumber;
+ ReleaseCallbackId() {}
+ ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber)
+ : bufferId(bufferId), framenumber(framenumber) {}
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ bool operator==(const ReleaseCallbackId& rhs) const {
+ return bufferId == rhs.bufferId && framenumber == rhs.framenumber;
+ }
+ bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); }
+ std::string to_string() const {
+ if (*this == INVALID_ID) return "INVALID_ID";
+
+ return "bufferId:" + std::to_string(bufferId) +
+ " framenumber:" + std::to_string(framenumber);
+ }
+};
+
struct ReleaseBufferCallbackIdHash {
std::size_t operator()(const ReleaseCallbackId& key) const {
return std::hash<uint64_t>()(key.bufferId);
@@ -161,6 +186,27 @@
std::vector<TransactionStats> transactionStats;
};
+class ITransactionCompletedListener : public IInterface {
+public:
+ DECLARE_META_INTERFACE(TransactionCompletedListener)
+
+ virtual void onTransactionCompleted(ListenerStats stats) = 0;
+
+ virtual void onReleaseBuffer(ReleaseCallbackId callbackId, sp<Fence> releaseFence,
+ uint32_t currentMaxAcquiredBufferCount) = 0;
+
+ virtual void onTransactionQueueStalled(const String8& name) = 0;
+};
+
+class BnTransactionCompletedListener : public SafeBnInterface<ITransactionCompletedListener> {
+public:
+ BnTransactionCompletedListener()
+ : SafeBnInterface<ITransactionCompletedListener>("BnTransactionCompletedListener") {}
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0) override;
+};
+
class ListenerCallbacks {
public:
ListenerCallbacks(const sp<IBinder>& listener,
@@ -222,4 +268,4 @@
}
};
-} // namespace android::gui
+} // namespace android
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c5fdf82..45a84f6 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -21,10 +21,10 @@
#include <stdint.h>
#include <sys/types.h>
-#include <android/gui/ITransactionCompletedListener.h>
#include <android/gui/IWindowInfosReportedListener.h>
#include <android/native_window.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
#include <android/gui/DropInputMode.h>
@@ -35,7 +35,6 @@
#include <gui/ISurfaceComposer.h>
#include <gui/LayerCaptureArgs.h>
#include <gui/LayerMetadata.h>
-#include <gui/ReleaseCallbackId.h>
#include <gui/SpHash.h>
#include <gui/SurfaceControl.h>
#include <gui/WindowInfo.h>
@@ -57,9 +56,6 @@
using gui::ISurfaceComposerClient;
using gui::LayerMetadata;
-using gui::ITransactionCompletedListener;
-using gui::ReleaseCallbackId;
-
struct client_cache_t {
wp<IBinder> token = nullptr;
uint64_t id;
diff --git a/libs/gui/include/gui/ReleaseCallbackId.h b/libs/gui/include/gui/ReleaseCallbackId.h
deleted file mode 100644
index 142ee5a..0000000
--- a/libs/gui/include/gui/ReleaseCallbackId.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2022 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.
- */
-
-#pragma once
-
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-
-#include <cstdint>
-
-namespace android::gui {
-
-class ReleaseCallbackId : public Parcelable {
-public:
- static const ReleaseCallbackId INVALID_ID;
-
- uint64_t bufferId;
- uint64_t framenumber;
- ReleaseCallbackId() {}
- ReleaseCallbackId(uint64_t bufferId, uint64_t framenumber)
- : bufferId(bufferId), framenumber(framenumber) {}
- status_t writeToParcel(Parcel* output) const override;
- status_t readFromParcel(const Parcel* input) override;
-
- bool operator==(const ReleaseCallbackId& rhs) const {
- return bufferId == rhs.bufferId && framenumber == rhs.framenumber;
- }
- bool operator!=(const ReleaseCallbackId& rhs) const { return !operator==(rhs); }
- std::string to_string() const {
- if (*this == INVALID_ID) return "INVALID_ID";
-
- return "bufferId:" + std::to_string(bufferId) +
- " framenumber:" + std::to_string(framenumber);
- }
-};
-
-} // namespace android::gui
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index cc459c5..2458a40 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -42,13 +42,10 @@
#include <android/gui/ISurfaceComposerClient.h>
-#include <android/gui/BnTransactionCompletedListener.h>
-
#include <gui/CpuConsumer.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
-#include <gui/ListenerStats.h>
-#include <gui/ReleaseCallbackId.h>
#include <gui/SurfaceControl.h>
#include <gui/WindowInfosListenerReporter.h>
#include <math/vec3.h>
@@ -62,21 +59,11 @@
class ITunnelModeEnabledListener;
class Region;
-using gui::BnTransactionCompletedListener;
-using gui::CallbackId;
-using gui::CallbackIdHash;
using gui::DisplayCaptureArgs;
-using gui::FrameEventHistoryStats;
using gui::IRegionSamplingListener;
using gui::ISurfaceComposerClient;
-using gui::ITransactionCompletedListener;
-using gui::JankData;
using gui::LayerCaptureArgs;
using gui::LayerMetadata;
-using gui::ListenerStats;
-using gui::ReleaseBufferCallbackIdHash;
-using gui::ReleaseCallbackId;
-using gui::SurfaceStats;
struct SurfaceControlStats {
SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime,
@@ -200,6 +187,11 @@
// Clears the user-preferred display mode
static status_t clearBootDisplayMode(const sp<IBinder>& display);
+ // Gets the HDR conversion capabilities of the device
+ static status_t getHdrConversionCapabilities(std::vector<gui::HdrConversionCapability>*);
+ // Sets the HDR conversion strategy for the device
+ static status_t setHdrConversionStrategy(gui::HdrConversionStrategy hdrConversionStrategy);
+
// Sets the frame rate of a particular app (uid). This is currently called
// by GameManager.
static status_t setOverrideFrameRate(uid_t uid, float frameRate);
@@ -841,17 +833,17 @@
void setReleaseBufferCallback(const ReleaseCallbackId&, ReleaseBufferCallback);
// BnTransactionCompletedListener overrides
- binder::Status onTransactionCompleted(const ListenerStats& stats) override;
- binder::Status onReleaseBuffer(const ReleaseCallbackId& callbackId,
- const std::optional<os::ParcelFileDescriptor>& releaseFenceFd,
- int32_t currentMaxAcquiredBufferCount) override;
- binder::Status onTransactionQueueStalled(const std::string& reason) override;
+ void onTransactionCompleted(ListenerStats stats) override;
+ void onReleaseBuffer(ReleaseCallbackId, sp<Fence> releaseFence,
+ uint32_t currentMaxAcquiredBufferCount) override;
void removeReleaseBufferCallback(const ReleaseCallbackId& callbackId);
// For Testing Only
static void setInstance(const sp<TransactionCompletedListener>&);
+ void onTransactionQueueStalled(const String8& reason) override;
+
private:
ReleaseBufferCallback popReleaseBufferCallbackLocked(const ReleaseCallbackId&);
static sp<TransactionCompletedListener> sInstance;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 55242df..3014804 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -819,6 +819,20 @@
return binder::Status::ok();
}
+ binder::Status getHdrConversionCapabilities(
+ std::vector<gui::HdrConversionCapability>*) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status setHdrConversionStrategy(
+ const gui::HdrConversionStrategy& /*hdrConversionStrategy*/) override {
+ return binder::Status::ok();
+ }
+
+ binder::Status getHdrOutputConversionSupport(bool* /*outSupport*/) override {
+ return binder::Status::ok();
+ }
+
binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override {
return binder::Status::ok();
}
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index 5c008b1..5720099 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -70,9 +70,10 @@
if (deltaY) {
mRawPositionY += *deltaY;
}
- mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)),
- {{AMOTION_EVENT_AXIS_X, {mRawPositionX}},
- {AMOTION_EVENT_AXIS_Y, {mRawPositionY}}});
+ mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_X,
+ mRawPositionX);
+ mVelocityTracker.addMovement(eventTime, /*pointerId=*/0, AMOTION_EVENT_AXIS_Y,
+ mRawPositionY);
std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 19b4684..1cd782d 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -23,6 +23,7 @@
#include <optional>
#include <android-base/stringprintf.h>
+#include <input/PrintTools.h>
#include <input/VelocityTracker.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
@@ -142,10 +143,7 @@
// --- VelocityTracker ---
VelocityTracker::VelocityTracker(const Strategy strategy)
- : mLastEventTime(0),
- mCurrentPointerIdBits(0),
- mActivePointerId(-1),
- mOverrideStrategy(strategy) {}
+ : mLastEventTime(0), mCurrentPointerIdBits(0), mOverrideStrategy(strategy) {}
VelocityTracker::~VelocityTracker() {
}
@@ -191,17 +189,17 @@
return std::make_unique<
LeastSquaresVelocityTrackerStrategy>(2,
LeastSquaresVelocityTrackerStrategy::
- WEIGHTING_DELTA);
+ Weighting::DELTA);
case VelocityTracker::Strategy::WLSQ2_CENTRAL:
return std::make_unique<
LeastSquaresVelocityTrackerStrategy>(2,
LeastSquaresVelocityTrackerStrategy::
- WEIGHTING_CENTRAL);
+ Weighting::CENTRAL);
case VelocityTracker::Strategy::WLSQ2_RECENT:
return std::make_unique<
LeastSquaresVelocityTrackerStrategy>(2,
LeastSquaresVelocityTrackerStrategy::
- WEIGHTING_RECENT);
+ Weighting::RECENT);
case VelocityTracker::Strategy::INT1:
return std::make_unique<IntegratingVelocityTrackerStrategy>(1);
@@ -220,30 +218,30 @@
void VelocityTracker::clear() {
mCurrentPointerIdBits.clear();
- mActivePointerId = -1;
+ mActivePointerId = std::nullopt;
mConfiguredStrategies.clear();
}
-void VelocityTracker::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value);
- mCurrentPointerIdBits = remainingIdBits;
+void VelocityTracker::clearPointer(int32_t pointerId) {
+ mCurrentPointerIdBits.clearBit(pointerId);
- if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
- mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
+ if (mActivePointerId && *mActivePointerId == pointerId) {
+ // The active pointer id is being removed. Mark it invalid and try to find a new one
+ // from the remaining pointers.
+ mActivePointerId = std::nullopt;
+ if (!mCurrentPointerIdBits.isEmpty()) {
+ mActivePointerId = mCurrentPointerIdBits.firstMarkedBit();
+ }
}
for (const auto& [_, strategy] : mConfiguredStrategies) {
- strategy->clearPointers(idBits);
+ strategy->clearPointer(pointerId);
}
}
-void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::map<int32_t /*axis*/, std::vector<float>>& positions) {
- while (idBits.count() > MAX_POINTERS) {
- idBits.clearLastMarkedBit();
- }
-
- if ((mCurrentPointerIdBits.value & idBits.value) &&
+void VelocityTracker::addMovement(nsecs_t eventTime, int32_t pointerId, int32_t axis,
+ float position) {
+ if (mCurrentPointerIdBits.hasBit(pointerId) &&
std::chrono::nanoseconds(eventTime - mLastEventTime) > ASSUME_POINTER_STOPPED_TIME) {
ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state.",
toString(std::chrono::nanoseconds(eventTime - mLastEventTime)).c_str());
@@ -254,39 +252,28 @@
}
mLastEventTime = eventTime;
- mCurrentPointerIdBits = idBits;
- if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
- mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
+ mCurrentPointerIdBits.markBit(pointerId);
+ if (!mActivePointerId) {
+ // Let this be the new active pointer if no active pointer is currently set
+ mActivePointerId = pointerId;
}
- for (const auto& [axis, positionValues] : positions) {
- LOG_ALWAYS_FATAL_IF(idBits.count() != positionValues.size(),
- "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
- idBits.count(), positionValues.size());
- if (mConfiguredStrategies.find(axis) == mConfiguredStrategies.end()) {
- configureStrategy(axis);
- }
- mConfiguredStrategies[axis]->addMovement(eventTime, idBits, positionValues);
+ if (mConfiguredStrategies.find(axis) == mConfiguredStrategies.end()) {
+ configureStrategy(axis);
}
+ mConfiguredStrategies[axis]->addMovement(eventTime, pointerId, position);
if (DEBUG_VELOCITY) {
- ALOGD("VelocityTracker: addMovement eventTime=%" PRId64
- ", idBits=0x%08x, activePointerId=%d",
- eventTime, idBits.value, mActivePointerId);
- for (const auto& positionsEntry : positions) {
- for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
- uint32_t id = iterBits.firstMarkedBit();
- uint32_t index = idBits.getIndexOfBit(id);
- iterBits.clearBit(id);
- Estimator estimator;
- getEstimator(positionsEntry.first, id, &estimator);
- ALOGD(" %d: axis=%d, position=%0.3f, "
- "estimator (degree=%d, coeff=%s, confidence=%f)",
- id, positionsEntry.first, positionsEntry.second[index], int(estimator.degree),
- vectorToString(estimator.coeff, estimator.degree + 1).c_str(),
- estimator.confidence);
- }
- }
+ ALOGD("VelocityTracker: addMovement eventTime=%" PRId64 ", pointerId=%" PRId32
+ ", activePointerId=%s",
+ eventTime, pointerId, toString(mActivePointerId).c_str());
+
+ std::optional<Estimator> estimator = getEstimator(axis, pointerId);
+ ALOGD(" %d: axis=%d, position=%0.3f, "
+ "estimator (degree=%d, coeff=%s, confidence=%f)",
+ pointerId, axis, position, int((*estimator).degree),
+ vectorToString((*estimator).coeff.data(), (*estimator).degree + 1).c_str(),
+ (*estimator).confidence);
}
}
@@ -296,94 +283,73 @@
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();
- axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
- 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);
- axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
- break;
- }
- case AMOTION_EVENT_ACTION_MOVE:
- case AMOTION_EVENT_ACTION_HOVER_MOVE:
- axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
- break;
- case AMOTION_EVENT_ACTION_POINTER_UP:
- case AMOTION_EVENT_ACTION_UP: {
- std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime);
- if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) {
- ALOGD_IF(DEBUG_VELOCITY,
- "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.",
- toString(delaySinceLastEvent).c_str());
- // We have not received any movements for too long. Assume that all pointers
- // have stopped.
- for (int32_t axis : PLANAR_AXES) {
- mConfiguredStrategies.erase(axis);
- }
+ case AMOTION_EVENT_ACTION_DOWN:
+ case AMOTION_EVENT_ACTION_HOVER_ENTER:
+ // Clear all pointers on down before adding the new movement.
+ clear();
+ axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
+ 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.
+ clearPointer(event->getPointerId(event->getActionIndex()));
+ axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
+ break;
}
- // These 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;
- }
- case AMOTION_EVENT_ACTION_SCROLL:
- axesToProcess.insert(AMOTION_EVENT_AXIS_SCROLL);
- break;
- default:
- // Ignore all other actions.
- 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));
- }
-
- std::map<int32_t, std::vector<float>> positions;
- for (int32_t axis : axesToProcess) {
- positions[axis].resize(pointerCount);
+ case AMOTION_EVENT_ACTION_MOVE:
+ case AMOTION_EVENT_ACTION_HOVER_MOVE:
+ axesToProcess.insert(PLANAR_AXES.begin(), PLANAR_AXES.end());
+ break;
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ case AMOTION_EVENT_ACTION_UP: {
+ std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime);
+ if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) {
+ ALOGD_IF(DEBUG_VELOCITY,
+ "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.",
+ toString(delaySinceLastEvent).c_str());
+ // We have not received any movements for too long. Assume that all pointers
+ // have stopped.
+ for (int32_t axis : PLANAR_AXES) {
+ mConfiguredStrategies.erase(axis);
+ }
+ }
+ // These 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;
+ }
+ case AMOTION_EVENT_ACTION_SCROLL:
+ axesToProcess.insert(AMOTION_EVENT_AXIS_SCROLL);
+ break;
+ default:
+ // Ignore all other actions.
+ return;
}
size_t historySize = event->getHistorySize();
for (size_t h = 0; h <= historySize; h++) {
nsecs_t eventTime = event->getHistoricalEventTime(h);
- for (int32_t axis : axesToProcess) {
- for (size_t i = 0; i < pointerCount; i++) {
- positions[axis][pointerIndex[i]] = event->getHistoricalAxisValue(axis, i, h);
+ for (size_t i = 0; i < event->getPointerCount(); i++) {
+ // TODO(b/167946721): skip resampled samples
+ const int32_t pointerId = event->getPointerId(i);
+ for (int32_t axis : axesToProcess) {
+ const float position = event->getHistoricalAxisValue(axis, i, h);
+ addMovement(eventTime, pointerId, axis, position);
}
}
- addMovement(eventTime, idBits, positions);
}
}
-std::optional<float> VelocityTracker::getVelocity(int32_t axis, uint32_t id) const {
- Estimator estimator;
- bool validVelocity = getEstimator(axis, id, &estimator) && estimator.degree >= 1;
- if (validVelocity) {
- return estimator.coeff[1];
+std::optional<float> VelocityTracker::getVelocity(int32_t axis, int32_t pointerId) const {
+ std::optional<Estimator> estimator = getEstimator(axis, pointerId);
+ if (estimator && (*estimator).degree >= 1) {
+ return (*estimator).coeff[1];
}
return {};
}
@@ -406,50 +372,55 @@
return computedVelocity;
}
-bool VelocityTracker::getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const {
+std::optional<VelocityTracker::Estimator> VelocityTracker::getEstimator(int32_t axis,
+ int32_t pointerId) const {
const auto& it = mConfiguredStrategies.find(axis);
if (it == mConfiguredStrategies.end()) {
- return false;
+ return std::nullopt;
}
- return it->second->getEstimator(id, outEstimator);
+ return it->second->getEstimator(pointerId);
}
// --- LeastSquaresVelocityTrackerStrategy ---
LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(uint32_t degree,
Weighting weighting)
- : mDegree(degree), mWeighting(weighting), mIndex(0) {}
+ : mDegree(degree), mWeighting(weighting) {}
LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {
}
-void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
- mMovements[mIndex].idBits = remainingIdBits;
+void LeastSquaresVelocityTrackerStrategy::clearPointer(int32_t pointerId) {
+ mIndex.erase(pointerId);
+ mMovements.erase(pointerId);
}
-void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) {
- if (mMovements[mIndex].eventTime != eventTime) {
+void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId,
+ float position) {
+ // If data for this pointer already exists, we have a valid entry at the position of
+ // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index
+ // to the next position in the circular buffer and write the new Movement there. Otherwise,
+ // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements
+ // for this pointer and write to the first position.
+ auto [movementIt, inserted] = mMovements.insert({pointerId, {}});
+ auto [indexIt, _] = mIndex.insert({pointerId, 0});
+ size_t& index = indexIt->second;
+ if (!inserted && movementIt->second[index].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
// the new pointer. If the eventtimes for both events are identical, just update the data
// for this time.
// We only compare against the last value, as it is likely that addMovement is called
// in chronological order as events occur.
- mIndex++;
+ index++;
}
- if (mIndex == HISTORY_SIZE) {
- mIndex = 0;
+ if (index == HISTORY_SIZE) {
+ index = 0;
}
- Movement& movement = mMovements[mIndex];
+ Movement& movement = movementIt->second[index];
movement.eventTime = eventTime;
- movement.idBits = idBits;
- uint32_t count = idBits.count();
- for (uint32_t i = 0; i < count; i++) {
- movement.positions[i] = positions[i];
- }
+ movement.position = position;
}
/**
@@ -502,7 +473,9 @@
* http://en.wikipedia.org/wiki/Gram-Schmidt
*/
static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
- const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
+ const std::vector<float>& w, uint32_t n,
+ std::array<float, VelocityTracker::Estimator::MAX_DEGREE + 1>& outB,
+ float* outDet) {
const size_t m = x.size();
ALOGD_IF(DEBUG_STRATEGY, "solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
@@ -583,7 +556,7 @@
outB[i] /= r[i][i];
}
- ALOGD_IF(DEBUG_STRATEGY, " - b=%s", vectorToString(outB, n).c_str());
+ ALOGD_IF(DEBUG_STRATEGY, " - b=%s", vectorToString(outB.data(), n).c_str());
// Calculate the coefficient of determination as 1 - (SSerr / SStot) where
// SSerr is the residual sum of squares (variance of the error),
@@ -671,37 +644,47 @@
return std::make_optional(std::array<float, 3>({c, b, a}));
}
-bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
- VelocityTracker::Estimator* outEstimator) const {
- outEstimator->clear();
-
+std::optional<VelocityTracker::Estimator> LeastSquaresVelocityTrackerStrategy::getEstimator(
+ int32_t pointerId) const {
+ const auto movementIt = mMovements.find(pointerId);
+ if (movementIt == mMovements.end()) {
+ return std::nullopt; // no data
+ }
// Iterate over movement samples in reverse time order and collect samples.
std::vector<float> positions;
std::vector<float> w;
std::vector<float> time;
- uint32_t index = mIndex;
- const Movement& newestMovement = mMovements[mIndex];
+ uint32_t index = mIndex.at(pointerId);
+ const Movement& newestMovement = movementIt->second[index];
do {
- const Movement& movement = mMovements[index];
- if (!movement.idBits.hasBit(id)) {
- break;
- }
+ const Movement& movement = movementIt->second[index];
nsecs_t age = newestMovement.eventTime - movement.eventTime;
if (age > HORIZON) {
break;
}
-
- positions.push_back(movement.getPosition(id));
- w.push_back(chooseWeight(index));
+ if (movement.eventTime == 0 && index != 0) {
+ // All eventTime's are initialized to 0. In this fixed-width circular buffer, it's
+ // possible that not all entries are valid. We use a time=0 as a signal for those
+ // uninitialized values. If we encounter a time of 0 in a position
+ // that's > 0, it means that we hit the block where the data wasn't initialized.
+ // We still don't know whether the value at index=0, with eventTime=0 is valid.
+ // However, that's only possible when the value is by itself. So there's no hard in
+ // processing it anyways, since the velocity for a single point is zero, and this
+ // situation will only be encountered in artificial circumstances (in tests).
+ // In practice, time will never be 0.
+ break;
+ }
+ positions.push_back(movement.position);
+ w.push_back(chooseWeight(pointerId, index));
time.push_back(-age * 0.000000001f);
index = (index == 0 ? HISTORY_SIZE : index) - 1;
} while (positions.size() < HISTORY_SIZE);
const size_t m = positions.size();
if (m == 0) {
- return false; // no data
+ return std::nullopt; // no data
}
// Calculate a least squares polynomial fit.
@@ -710,112 +693,116 @@
degree = m - 1;
}
- if (degree == 2 && mWeighting == WEIGHTING_NONE) {
+ if (degree == 2 && mWeighting == Weighting::NONE) {
// Optimize unweighted, quadratic polynomial fit
std::optional<std::array<float, 3>> coeff =
solveUnweightedLeastSquaresDeg2(time, positions);
if (coeff) {
- outEstimator->time = newestMovement.eventTime;
- outEstimator->degree = 2;
- outEstimator->confidence = 1;
- for (size_t i = 0; i <= outEstimator->degree; i++) {
- outEstimator->coeff[i] = (*coeff)[i];
+ VelocityTracker::Estimator estimator;
+ estimator.time = newestMovement.eventTime;
+ estimator.degree = 2;
+ estimator.confidence = 1;
+ for (size_t i = 0; i <= estimator.degree; i++) {
+ estimator.coeff[i] = (*coeff)[i];
}
- return true;
+ return estimator;
}
} else if (degree >= 1) {
// General case for an Nth degree polynomial fit
float det;
uint32_t n = degree + 1;
- if (solveLeastSquares(time, positions, w, n, outEstimator->coeff, &det)) {
- outEstimator->time = newestMovement.eventTime;
- outEstimator->degree = degree;
- outEstimator->confidence = det;
+ VelocityTracker::Estimator estimator;
+ if (solveLeastSquares(time, positions, w, n, estimator.coeff, &det)) {
+ estimator.time = newestMovement.eventTime;
+ estimator.degree = degree;
+ estimator.confidence = det;
ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, coeff=%s, confidence=%f",
- int(outEstimator->degree), vectorToString(outEstimator->coeff, n).c_str(),
- outEstimator->confidence);
+ int(estimator.degree), vectorToString(estimator.coeff.data(), n).c_str(),
+ estimator.confidence);
- return true;
+ return estimator;
}
}
// No velocity data available for this pointer, but we do have its current position.
- outEstimator->coeff[0] = positions[0];
- outEstimator->time = newestMovement.eventTime;
- outEstimator->degree = 0;
- outEstimator->confidence = 1;
- return true;
+ VelocityTracker::Estimator estimator;
+ estimator.coeff[0] = positions[0];
+ estimator.time = newestMovement.eventTime;
+ estimator.degree = 0;
+ estimator.confidence = 1;
+ return estimator;
}
-float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const {
+float LeastSquaresVelocityTrackerStrategy::chooseWeight(int32_t pointerId, uint32_t index) const {
+ const std::array<Movement, HISTORY_SIZE>& movements = mMovements.at(pointerId);
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) {
+ 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.at(pointerId)) {
+ return 1.0f;
+ }
+ uint32_t nextIndex = (index + 1) % HISTORY_SIZE;
+ float deltaMillis =
+ (movements[nextIndex].eventTime - movements[index].eventTime) * 0.000001f;
+ if (deltaMillis < 0) {
+ return 0.5f;
+ }
+ if (deltaMillis < 10) {
+ return 0.5f + deltaMillis * 0.05;
+ }
return 1.0f;
}
- uint32_t nextIndex = (index + 1) % HISTORY_SIZE;
- float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime)
- * 0.000001f;
- if (deltaMillis < 0) {
+
+ 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 =
+ (movements[mIndex.at(pointerId)].eventTime - movements[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;
}
- 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) {
+ 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 =
+ (movements[mIndex.at(pointerId)].eventTime - movements[index].eventTime) *
+ 0.000001f;
+ if (ageMillis < 50) {
+ return 1.0f;
+ }
+ if (ageMillis < 100) {
+ return 0.5f + (100 - ageMillis) * 0.01f;
+ }
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) {
+ case Weighting::NONE:
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) :
@@ -825,38 +812,32 @@
IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
}
-void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- mPointerIdBits.value &= ~idBits.value;
+void IntegratingVelocityTrackerStrategy::clearPointer(int32_t pointerId) {
+ mPointerIdBits.clearBit(pointerId);
}
-void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) {
- uint32_t index = 0;
- for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
- uint32_t id = iterIdBits.clearFirstMarkedBit();
- State& state = mPointerState[id];
- const float position = positions[index++];
- if (mPointerIdBits.hasBit(id)) {
- updateState(state, eventTime, position);
- } else {
- initState(state, eventTime, position);
- }
+void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId,
+ float position) {
+ State& state = mPointerState[pointerId];
+ if (mPointerIdBits.hasBit(pointerId)) {
+ updateState(state, eventTime, position);
+ } else {
+ initState(state, eventTime, position);
}
- mPointerIdBits = idBits;
+ mPointerIdBits.markBit(pointerId);
}
-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;
+std::optional<VelocityTracker::Estimator> IntegratingVelocityTrackerStrategy::getEstimator(
+ int32_t pointerId) const {
+ if (mPointerIdBits.hasBit(pointerId)) {
+ const State& state = mPointerState[pointerId];
+ VelocityTracker::Estimator estimator;
+ populateEstimator(state, &estimator);
+ return estimator;
}
- return false;
+ return std::nullopt;
}
void IntegratingVelocityTrackerStrategy::initState(State& state, nsecs_t eventTime,
@@ -916,49 +897,60 @@
// --- LegacyVelocityTrackerStrategy ---
-LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() : mIndex(0) {}
+LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {}
LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() {
}
-void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
- mMovements[mIndex].idBits = remainingIdBits;
+void LegacyVelocityTrackerStrategy::clearPointer(int32_t pointerId) {
+ mIndex.erase(pointerId);
+ mMovements.erase(pointerId);
}
-void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) {
- if (++mIndex == HISTORY_SIZE) {
- mIndex = 0;
+void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId,
+ float position) {
+ // If data for this pointer already exists, we have a valid entry at the position of
+ // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index
+ // to the next position in the circular buffer and write the new Movement there. Otherwise,
+ // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements
+ // for this pointer and write to the first position.
+ auto [movementIt, inserted] = mMovements.insert({pointerId, {}});
+ auto [indexIt, _] = mIndex.insert({pointerId, 0});
+ size_t& index = indexIt->second;
+ if (!inserted && movementIt->second[index].eventTime != eventTime) {
+ // When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
+ // of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
+ // the new pointer. If the eventtimes for both events are identical, just update the data
+ // for this time.
+ // We only compare against the last value, as it is likely that addMovement is called
+ // in chronological order as events occur.
+ index++;
+ }
+ if (index == HISTORY_SIZE) {
+ index = 0;
}
- Movement& movement = mMovements[mIndex];
+ Movement& movement = movementIt->second[index];
movement.eventTime = eventTime;
- movement.idBits = idBits;
- uint32_t count = idBits.count();
- for (uint32_t i = 0; i < count; i++) {
- movement.positions[i] = positions[i];
- }
+ movement.position = position;
}
-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
+std::optional<VelocityTracker::Estimator> LegacyVelocityTrackerStrategy::getEstimator(
+ int32_t pointerId) const {
+ const auto movementIt = mMovements.find(pointerId);
+ if (movementIt == mMovements.end()) {
+ return std::nullopt; // no data
}
+ const Movement& newestMovement = movementIt->second[mIndex.at(pointerId)];
// 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 oldestIndex = mIndex.at(pointerId);
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) {
+ const Movement& nextOldestMovement = mMovements.at(pointerId)[nextOldestIndex];
+ if (nextOldestMovement.eventTime < minTime) {
break;
}
oldestIndex = nextOldestIndex;
@@ -978,22 +970,22 @@
float accumV = 0;
uint32_t index = oldestIndex;
uint32_t samplesUsed = 0;
- const Movement& oldestMovement = mMovements[oldestIndex];
- float oldestPosition = oldestMovement.getPosition(id);
+ const Movement& oldestMovement = mMovements.at(pointerId)[oldestIndex];
+ float oldestPosition = oldestMovement.position;
nsecs_t lastDuration = 0;
while (numTouches-- > 1) {
if (++index == HISTORY_SIZE) {
index = 0;
}
- const Movement& movement = mMovements[index];
+ const Movement& movement = mMovements.at(pointerId)[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) {
- float position = movement.getPosition(id);
+ float position = movement.position;
float scale = 1000000000.0f / duration; // one over time delta in seconds
float v = (position - oldestPosition) * scale;
accumV = (accumV * lastDuration + v * duration) / (duration + lastDuration);
@@ -1003,54 +995,59 @@
}
// Report velocity.
- float newestPosition = newestMovement.getPosition(id);
- outEstimator->time = newestMovement.eventTime;
- outEstimator->confidence = 1;
- outEstimator->coeff[0] = newestPosition;
+ float newestPosition = newestMovement.position;
+ VelocityTracker::Estimator estimator;
+ estimator.time = newestMovement.eventTime;
+ estimator.confidence = 1;
+ estimator.coeff[0] = newestPosition;
if (samplesUsed) {
- outEstimator->coeff[1] = accumV;
- outEstimator->degree = 1;
+ estimator.coeff[1] = accumV;
+ estimator.degree = 1;
} else {
- outEstimator->degree = 0;
+ estimator.degree = 0;
}
- return true;
+ return estimator;
}
// --- ImpulseVelocityTrackerStrategy ---
ImpulseVelocityTrackerStrategy::ImpulseVelocityTrackerStrategy(bool deltaValues)
- : mDeltaValues(deltaValues), mIndex(0) {}
+ : mDeltaValues(deltaValues) {}
ImpulseVelocityTrackerStrategy::~ImpulseVelocityTrackerStrategy() {
}
-void ImpulseVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
- BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
- mMovements[mIndex].idBits = remainingIdBits;
+void ImpulseVelocityTrackerStrategy::clearPointer(int32_t pointerId) {
+ mIndex.erase(pointerId);
+ mMovements.erase(pointerId);
}
-void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) {
- if (mMovements[mIndex].eventTime != eventTime) {
+void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, int32_t pointerId,
+ float position) {
+ // If data for this pointer already exists, we have a valid entry at the position of
+ // mIndex[pointerId] and mMovements[pointerId]. In that case, we need to advance the index
+ // to the next position in the circular buffer and write the new Movement there. Otherwise,
+ // if this is a first movement for this pointer, we initialize the maps mIndex and mMovements
+ // for this pointer and write to the first position.
+ auto [movementIt, inserted] = mMovements.insert({pointerId, {}});
+ auto [indexIt, _] = mIndex.insert({pointerId, 0});
+ size_t& index = indexIt->second;
+ if (!inserted && movementIt->second[index].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
// the new pointer. If the eventtimes for both events are identical, just update the data
// for this time.
// We only compare against the last value, as it is likely that addMovement is called
// in chronological order as events occur.
- mIndex++;
+ index++;
}
- if (mIndex == HISTORY_SIZE) {
- mIndex = 0;
+ if (index == HISTORY_SIZE) {
+ index = 0;
}
- Movement& movement = mMovements[mIndex];
+ Movement& movement = movementIt->second[index];
movement.eventTime = eventTime;
- movement.idBits = idBits;
- uint32_t count = idBits.count();
- for (uint32_t i = 0; i < count; i++) {
- movement.positions[i] = positions[i];
- }
+ movement.position = position;
}
/**
@@ -1178,55 +1175,61 @@
return kineticEnergyToVelocity(work);
}
-bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id,
- VelocityTracker::Estimator* outEstimator) const {
- outEstimator->clear();
+std::optional<VelocityTracker::Estimator> ImpulseVelocityTrackerStrategy::getEstimator(
+ int32_t pointerId) const {
+ const auto movementIt = mMovements.find(pointerId);
+ if (movementIt == mMovements.end()) {
+ return std::nullopt; // no data
+ }
// Iterate over movement samples in reverse time order and collect samples.
float positions[HISTORY_SIZE];
nsecs_t time[HISTORY_SIZE];
size_t m = 0; // number of points that will be used for fitting
- size_t index = mIndex;
- const Movement& newestMovement = mMovements[mIndex];
+ size_t index = mIndex.at(pointerId);
+ const Movement& newestMovement = movementIt->second[index];
do {
- const Movement& movement = mMovements[index];
- if (!movement.idBits.hasBit(id)) {
- break;
- }
+ const Movement& movement = movementIt->second[index];
nsecs_t age = newestMovement.eventTime - movement.eventTime;
if (age > HORIZON) {
break;
}
+ if (movement.eventTime == 0 && index != 0) {
+ // All eventTime's are initialized to 0. If we encounter a time of 0 in a position
+ // that's >0, it means that we hit the block where the data wasn't initialized.
+ // It's also possible that the sample at 0 would be invalid, but there's no harm in
+ // processing it, since it would be just a single point, and will only be encountered
+ // in artificial circumstances (in tests).
+ break;
+ }
- positions[m] = movement.getPosition(id);
+ positions[m] = movement.position;
time[m] = movement.eventTime;
index = (index == 0 ? HISTORY_SIZE : index) - 1;
} while (++m < HISTORY_SIZE);
if (m == 0) {
- return false; // no data
+ return std::nullopt; // no data
}
- outEstimator->coeff[0] = 0;
- outEstimator->coeff[1] = calculateImpulseVelocity(time, positions, m, mDeltaValues);
- outEstimator->coeff[2] = 0;
+ VelocityTracker::Estimator estimator;
+ estimator.coeff[0] = 0;
+ estimator.coeff[1] = calculateImpulseVelocity(time, positions, m, mDeltaValues);
+ estimator.coeff[2] = 0;
- outEstimator->time = newestMovement.eventTime;
- outEstimator->degree = 2; // similar results to 2nd degree fit
- outEstimator->confidence = 1;
+ estimator.time = newestMovement.eventTime;
+ estimator.degree = 2; // similar results to 2nd degree fit
+ estimator.confidence = 1;
- ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", outEstimator->coeff[1]);
+ ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", estimator.coeff[1]);
if (DEBUG_IMPULSE) {
// TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
// Calculate the lsq2 velocity for the same inputs to allow runtime comparisons.
// X axis chosen arbitrarily for velocity comparisons.
VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2);
- BitSet32 idBits;
- const uint32_t pointerId = 0;
- idBits.markBit(pointerId);
for (ssize_t i = m - 1; i >= 0; i--) {
- lsq2.addMovement(time[i], idBits, {{AMOTION_EVENT_AXIS_X, {positions[i]}}});
+ lsq2.addMovement(time[i], pointerId, AMOTION_EVENT_AXIS_X, positions[i]);
}
std::optional<float> v = lsq2.getVelocity(AMOTION_EVENT_AXIS_X, pointerId);
if (v) {
@@ -1235,7 +1238,7 @@
ALOGD("lsq2 velocity: could not compute velocity");
}
}
- return true;
+ return estimator;
}
} // namespace android
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 54feea2..2678f2f 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -288,13 +288,13 @@
for (MotionEvent event : events) {
vt.addMovement(&event);
}
- VelocityTracker::Estimator estimatorX;
- VelocityTracker::Estimator estimatorY;
- EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_X, 0, &estimatorX));
- EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0, &estimatorY));
+ std::optional<VelocityTracker::Estimator> estimatorX = vt.getEstimator(AMOTION_EVENT_AXIS_X, 0);
+ std::optional<VelocityTracker::Estimator> estimatorY = vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0);
+ EXPECT_TRUE(estimatorX);
+ EXPECT_TRUE(estimatorY);
for (size_t i = 0; i< coefficients.size(); i++) {
- checkCoefficient(estimatorX.coeff[i], coefficients[i]);
- checkCoefficient(estimatorY.coeff[i], coefficients[i]);
+ checkCoefficient((*estimatorX).coeff[i], coefficients[i]);
+ checkCoefficient((*estimatorY).coeff[i], coefficients[i]);
}
}
@@ -420,8 +420,7 @@
EXPECT_FALSE(vt.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID));
- VelocityTracker::Estimator estimator;
- EXPECT_FALSE(vt.getEstimator(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID, &estimator));
+ EXPECT_FALSE(vt.getEstimator(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID));
VelocityTracker::ComputedVelocity computedVelocity = vt.getComputedVelocity(1000, 1000);
for (uint32_t id = 0; id <= MAX_POINTER_ID; id++) {
@@ -432,7 +431,7 @@
EXPECT_EQ(-1, vt.getActivePointerId());
// Make sure that the clearing functions execute without an issue.
- vt.clearPointers(BitSet32(7U));
+ vt.clearPointer(7U);
vt.clear();
}
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 4d51aee..8cd2cf0 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -2703,18 +2703,15 @@
// Update the velocity tracker.
{
- std::vector<float> positionsX;
- std::vector<float> positionsY;
for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
mCurrentRawState.rawPointerData.pointerForId(id);
- positionsX.push_back(pointer.x * mPointerXMovementScale);
- positionsY.push_back(pointer.y * mPointerYMovementScale);
+ const float x = pointer.x * mPointerXMovementScale;
+ const float y = pointer.y * mPointerYMovementScale;
+ mPointerGesture.velocityTracker.addMovement(when, id, AMOTION_EVENT_AXIS_X, x);
+ mPointerGesture.velocityTracker.addMovement(when, id, AMOTION_EVENT_AXIS_Y, y);
}
- mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
- {{AMOTION_EVENT_AXIS_X, positionsX},
- {AMOTION_EVENT_AXIS_Y, positionsY}});
}
// If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 33caa7a..6199a5a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -112,6 +112,11 @@
MOCK_METHOD1(clearBootDisplayMode, status_t(PhysicalDisplayId));
MOCK_METHOD1(getPreferredBootDisplayMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
MOCK_METHOD0(getBootDisplayModeSupport, bool());
+ MOCK_CONST_METHOD0(
+ getHdrConversionCapabilities,
+ std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>());
+ MOCK_METHOD1(setHdrConversionStrategy,
+ status_t(aidl::android::hardware::graphics::common::HdrConversionStrategy));
MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
MOCK_METHOD(status_t, getSupportedContentTypes,
(PhysicalDisplayId, std::vector<hal::ContentType>*), (const, override));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index bd5d21a..0982077 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -171,7 +171,7 @@
void DisplayDevice::setPowerMode(hal::PowerMode mode) {
if (mode == hal::PowerMode::OFF || mode == hal::PowerMode::ON) {
- if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ if (mStagedBrightness && mBrightness != mStagedBrightness) {
getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
mBrightness = *mStagedBrightness;
}
@@ -298,7 +298,7 @@
}
void DisplayDevice::persistBrightness(bool needsComposite) {
- if (mStagedBrightness && mBrightness != *mStagedBrightness) {
+ if (mStagedBrightness && mBrightness != mStagedBrightness) {
if (needsComposite) {
getCompositionDisplay()->setNextBrightness(*mStagedBrightness);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 08d64f1..370bd66 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -272,7 +272,7 @@
std::optional<hardware::graphics::composer::hal::PowerMode> mPowerMode;
std::optional<float> mStagedBrightness;
- float mBrightness = -1.f;
+ std::optional<float> mBrightness;
// TODO(b/182939859): Remove special cases for primary display.
const bool mIsPrimary;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index e372b72..9470552 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -56,6 +56,9 @@
using AidlDisplayAttribute = aidl::android::hardware::graphics::composer3::DisplayAttribute;
using AidlDisplayCapability = aidl::android::hardware::graphics::composer3::DisplayCapability;
using AidlHdrCapabilities = aidl::android::hardware::graphics::composer3::HdrCapabilities;
+using AidlHdrConversionCapability =
+ aidl::android::hardware::graphics::common::HdrConversionCapability;
+using AidlHdrConversionStrategy = aidl::android::hardware::graphics::common::HdrConversionStrategy;
using AidlOverlayProperties = aidl::android::hardware::graphics::composer3::OverlayProperties;
using AidlPerFrameMetadata = aidl::android::hardware::graphics::composer3::PerFrameMetadata;
using AidlPerFrameMetadataKey = aidl::android::hardware::graphics::composer3::PerFrameMetadataKey;
@@ -1396,6 +1399,27 @@
return Error::NONE;
}
+Error AidlComposer::getHdrConversionCapabilities(
+ std::vector<AidlHdrConversionCapability>* hdrConversionCapabilities) {
+ const auto status =
+ mAidlComposerClient->getHdrConversionCapabilities(hdrConversionCapabilities);
+ if (!status.isOk()) {
+ hdrConversionCapabilities = {};
+ ALOGE("getHdrConversionCapabilities failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
+Error AidlComposer::setHdrConversionStrategy(AidlHdrConversionStrategy hdrConversionStrategy) {
+ const auto status = mAidlComposerClient->setHdrConversionStrategy(hdrConversionStrategy);
+ if (!status.isOk()) {
+ ALOGE("setHdrConversionStrategy failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+ return Error::NONE;
+}
+
Error AidlComposer::getClientTargetProperty(
Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
Error error = Error::NONE;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 9a7ade7..a5ddf74 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -48,6 +48,8 @@
namespace android::Hwc2 {
using aidl::android::hardware::graphics::common::DisplayDecorationSupport;
+using aidl::android::hardware::graphics::common::HdrConversionCapability;
+using aidl::android::hardware::graphics::common::HdrConversionStrategy;
using aidl::android::hardware::graphics::composer3::ComposerClientReader;
using aidl::android::hardware::graphics::composer3::ComposerClientWriter;
using aidl::android::hardware::graphics::composer3::OverlayProperties;
@@ -235,6 +237,8 @@
AidlTransform* outDisplayOrientation) override;
void onHotplugConnect(Display) override;
void onHotplugDisconnect(Display) override;
+ Error getHdrConversionCapabilities(std::vector<HdrConversionCapability>*) override;
+ Error setHdrConversionStrategy(HdrConversionStrategy) override;
private:
// Many public functions above simply write a command into the command
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 1c2b8b5..82b677e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -32,6 +32,8 @@
#include <utils/StrongPointer.h>
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/common/HdrConversionCapability.h>
+#include <aidl/android/hardware/graphics/common/HdrConversionStrategy.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Color.h>
@@ -288,6 +290,10 @@
virtual Error getOverlaySupport(V3_0::OverlayProperties* outProperties) = 0;
virtual void onHotplugConnect(Display) = 0;
virtual void onHotplugDisconnect(Display) = 0;
+ virtual Error getHdrConversionCapabilities(
+ std::vector<::aidl::android::hardware::graphics::common::HdrConversionCapability>*) = 0;
+ virtual Error setHdrConversionStrategy(
+ ::aidl::android::hardware::graphics::common::HdrConversionStrategy) = 0;
};
} // namespace Hwc2
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 10fde2a..7dde6b4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -70,6 +70,8 @@
#define RETURN_IF_HWC_ERROR(error, displayId, ...) \
RETURN_IF_HWC_ERROR_FOR(__FUNCTION__, error, displayId, __VA_ARGS__)
+using aidl::android::hardware::graphics::common::HdrConversionCapability;
+using aidl::android::hardware::graphics::common::HdrConversionStrategy;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::DisplayCapability;
namespace hal = android::hardware::graphics::composer::hal;
@@ -97,6 +99,7 @@
loadCapabilities();
loadLayerMetadataSupport();
loadOverlayProperties();
+ loadHdrConversionCapabilities();
if (mRegisteredCallback) {
ALOGW("Callback already registered. Ignored extra registration attempt.");
@@ -787,6 +790,18 @@
return displayModeId;
}
+std::vector<HdrConversionCapability> HWComposer::getHdrConversionCapabilities() const {
+ return mHdrConversionCapabilities;
+}
+
+status_t HWComposer::setHdrConversionStrategy(HdrConversionStrategy hdrConversionStrategy) {
+ const auto error = mComposer->setHdrConversionStrategy(hdrConversionStrategy);
+ if (error != hal::Error::NONE) {
+ ALOGE("Error in setting HDR conversion strategy %s", to_string(error).c_str());
+ }
+ return NO_ERROR;
+}
+
status_t HWComposer::getDisplayDecorationSupport(
PhysicalDisplayId displayId,
std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>*
@@ -979,6 +994,14 @@
mComposer->getOverlaySupport(&mOverlayProperties);
}
+void HWComposer::loadHdrConversionCapabilities() {
+ const auto error = mComposer->getHdrConversionCapabilities(&mHdrConversionCapabilities);
+ if (error != hal::Error::NONE) {
+ ALOGE("Error in fetching HDR conversion capabilities %s", to_string(error).c_str());
+ mHdrConversionCapabilities = {};
+ }
+}
+
status_t HWComposer::setIdleTimerEnabled(PhysicalDisplayId displayId,
std::chrono::milliseconds timeout) {
ATRACE_CALL();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 78d4a68..f6155d2 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -44,6 +44,8 @@
#include "Hal.h"
#include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
+#include <aidl/android/hardware/graphics/common/HdrConversionCapability.h>
+#include <aidl/android/hardware/graphics/common/HdrConversionStrategy.h>
#include <aidl/android/hardware/graphics/composer3/Capability.h>
#include <aidl/android/hardware/graphics/composer3/ClientTargetPropertyWithBrightness.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
@@ -286,6 +288,10 @@
virtual status_t setIdleTimerEnabled(PhysicalDisplayId, std::chrono::milliseconds timeout) = 0;
virtual bool hasDisplayIdleTimerCapability(PhysicalDisplayId) const = 0;
virtual Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const = 0;
+ virtual std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>
+ getHdrConversionCapabilities() const = 0;
+ virtual status_t setHdrConversionStrategy(
+ aidl::android::hardware::graphics::common::HdrConversionStrategy) = 0;
};
static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs,
@@ -437,6 +443,10 @@
status_t setIdleTimerEnabled(PhysicalDisplayId, std::chrono::milliseconds timeout) override;
bool hasDisplayIdleTimerCapability(PhysicalDisplayId) const override;
Hwc2::AidlTransform getPhysicalDisplayOrientation(PhysicalDisplayId) const override;
+ std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>
+ getHdrConversionCapabilities() const override;
+ status_t setHdrConversionStrategy(
+ aidl::android::hardware::graphics::common::HdrConversionStrategy) override;
// for debugging ----------------------------------------------------------
void dump(std::string& out) const override;
@@ -490,12 +500,16 @@
void loadCapabilities();
void loadLayerMetadataSupport();
void loadOverlayProperties();
+ void loadHdrConversionCapabilities();
std::unordered_map<HalDisplayId, DisplayData> mDisplayData;
std::unique_ptr<android::Hwc2::Composer> mComposer;
std::unordered_set<aidl::android::hardware::graphics::composer3::Capability> mCapabilities;
aidl::android::hardware::graphics::composer3::OverlayProperties mOverlayProperties;
+ std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>
+ mHdrConversionCapabilities = {};
+
std::unordered_map<std::string, bool> mSupportedLayerGenericMetadata;
bool mRegisteredCallback = false;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index c9e1e79..6fdb2d7 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -36,6 +36,8 @@
#include <algorithm>
#include <cinttypes>
+using aidl::android::hardware::graphics::common::HdrConversionCapability;
+using aidl::android::hardware::graphics::common::HdrConversionStrategy;
using aidl::android::hardware::graphics::composer3::Capability;
using aidl::android::hardware::graphics::composer3::ClientTargetPropertyWithBrightness;
using aidl::android::hardware::graphics::composer3::DimmingStage;
@@ -1348,6 +1350,14 @@
return Error::UNSUPPORTED;
}
+Error HidlComposer::getHdrConversionCapabilities(std::vector<HdrConversionCapability>*) {
+ return Error::UNSUPPORTED;
+}
+
+Error HidlComposer::setHdrConversionStrategy(HdrConversionStrategy) {
+ return Error::UNSUPPORTED;
+}
+
Error HidlComposer::getClientTargetProperty(
Display display, ClientTargetPropertyWithBrightness* outClientTargetProperty) {
IComposerClient::ClientTargetProperty property;
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 921add5..8280af2 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -343,6 +343,11 @@
AidlTransform* outDisplayOrientation) override;
void onHotplugConnect(Display) override;
void onHotplugDisconnect(Display) override;
+ Error getHdrConversionCapabilities(
+ std::vector<aidl::android::hardware::graphics::common::HdrConversionCapability>*)
+ override;
+ Error setHdrConversionStrategy(
+ aidl::android::hardware::graphics::common::HdrConversionStrategy) override;
private:
class CommandWriter : public CommandWriterBase {
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index c2109b3..8629671 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -177,7 +177,7 @@
}
mStalledTransactions.push_back(transactionId);
- listener->onTransactionQueueStalled(reason);
+ listener->onTransactionQueueStalled(String8(reason.c_str()));
}
void TransactionHandler::removeFromStalledTransactions(uint64_t id) {
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.h b/services/surfaceflinger/FrontEnd/TransactionHandler.h
index 475ff1b..a06b870 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.h
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.h
@@ -29,7 +29,6 @@
namespace android {
class TestableSurfaceFlinger;
-using gui::IListenerHash;
namespace surfaceflinger::frontend {
class TransactionHandler {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1f159ae..de9ea04 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2604,12 +2604,9 @@
return;
}
ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber);
- std::optional<os::ParcelFileDescriptor> fenceFd;
- if (releaseFence) {
- fenceFd = os::ParcelFileDescriptor(base::unique_fd(::dup(releaseFence->get())));
- }
- listener->onReleaseBuffer({buffer->getId(), framenumber}, fenceFd,
- static_cast<int32_t>(currentMaxAcquiredBufferCount));
+ listener->onReleaseBuffer({buffer->getId(), framenumber},
+ releaseFence ? releaseFence : Fence::NO_FENCE,
+ currentMaxAcquiredBufferCount);
}
void Layer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 771c09e..2d8b9c1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1540,6 +1540,80 @@
return future.get();
}
+status_t SurfaceFlinger::getHdrConversionCapabilities(
+ std::vector<gui::HdrConversionCapability>* hdrConversionCapabilities) const {
+ bool hdrOutputConversionSupport;
+ getHdrOutputConversionSupport(&hdrOutputConversionSupport);
+ if (hdrOutputConversionSupport == false) {
+ ALOGE("hdrOutputConversion is not supported by this device.");
+ return INVALID_OPERATION;
+ }
+ const auto aidlConversionCapability = getHwComposer().getHdrConversionCapabilities();
+ for (auto capability : aidlConversionCapability) {
+ gui::HdrConversionCapability tempCapability;
+ tempCapability.sourceType = static_cast<int>(capability.sourceType.hdr);
+ tempCapability.outputType = static_cast<int>(capability.outputType->hdr);
+ tempCapability.addsLatency = capability.addsLatency;
+ hdrConversionCapabilities->push_back(tempCapability);
+ }
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setHdrConversionStrategy(
+ const gui::HdrConversionStrategy& hdrConversionStrategy) {
+ bool hdrOutputConversionSupport;
+ getHdrOutputConversionSupport(&hdrOutputConversionSupport);
+ if (hdrOutputConversionSupport == false) {
+ ALOGE("hdrOutputConversion is not supported by this device.");
+ return INVALID_OPERATION;
+ }
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) mutable -> status_t {
+ using AidlHdrConversionStrategy =
+ aidl::android::hardware::graphics::common::HdrConversionStrategy;
+ using GuiHdrConversionStrategyTag = gui::HdrConversionStrategy::Tag;
+ AidlHdrConversionStrategy aidlConversionStrategy;
+ switch (hdrConversionStrategy.getTag()) {
+ case GuiHdrConversionStrategyTag::passthrough: {
+ aidlConversionStrategy.set<AidlHdrConversionStrategy::Tag::passthrough>(
+ hdrConversionStrategy.get<GuiHdrConversionStrategyTag::passthrough>());
+ return getHwComposer().setHdrConversionStrategy(aidlConversionStrategy);
+ }
+ case GuiHdrConversionStrategyTag::autoAllowedHdrTypes: {
+ auto autoHdrTypes =
+ hdrConversionStrategy
+ .get<GuiHdrConversionStrategyTag::autoAllowedHdrTypes>();
+ std::vector<aidl::android::hardware::graphics::common::Hdr> aidlAutoHdrTypes;
+ for (auto type : autoHdrTypes) {
+ aidlAutoHdrTypes.push_back(
+ static_cast<aidl::android::hardware::graphics::common::Hdr>(type));
+ }
+ aidlConversionStrategy.set<AidlHdrConversionStrategy::Tag::autoAllowedHdrTypes>(
+ aidlAutoHdrTypes);
+ return getHwComposer().setHdrConversionStrategy(aidlConversionStrategy);
+ }
+ case GuiHdrConversionStrategyTag::forceHdrConversion: {
+ auto forceHdrConversion =
+ hdrConversionStrategy
+ .get<GuiHdrConversionStrategyTag::forceHdrConversion>();
+ aidlConversionStrategy.set<AidlHdrConversionStrategy::Tag::forceHdrConversion>(
+ static_cast<aidl::android::hardware::graphics::common::Hdr>(
+ forceHdrConversion));
+ return getHwComposer().setHdrConversionStrategy(aidlConversionStrategy);
+ }
+ }
+ });
+ return future.get();
+}
+
+status_t SurfaceFlinger::getHdrOutputConversionSupport(bool* outSupport) const {
+ auto future = mScheduler->schedule([this] {
+ return getHwComposer().hasCapability(Capability::HDR_OUTPUT_CONVERSION_CONFIG);
+ });
+
+ *outSupport = future.get();
+ return NO_ERROR;
+}
+
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
const char* const whence = __func__;
static_cast<void>(mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
@@ -7160,7 +7234,8 @@
layerName, static_cast<uint32_t>(mMaxRenderTargetSize));
ALOGD("%s", errorMessage.c_str());
if (bufferData.releaseBufferListener) {
- bufferData.releaseBufferListener->onTransactionQueueStalled(errorMessage);
+ bufferData.releaseBufferListener->onTransactionQueueStalled(
+ String8(errorMessage.c_str()));
}
return nullptr;
}
@@ -7178,7 +7253,7 @@
if (bufferData.releaseBufferListener) {
bufferData.releaseBufferListener->onTransactionQueueStalled(
- "Buffer processing hung due to full buffer cache");
+ String8("Buffer processing hung due to full buffer cache"));
}
}
@@ -7584,6 +7659,32 @@
return binderStatusFromStatusT(status);
}
+binder::Status SurfaceComposerAIDL::getHdrConversionCapabilities(
+ std::vector<gui::HdrConversionCapability>* hdrConversionCapabilities) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ status = mFlinger->getHdrConversionCapabilities(hdrConversionCapabilities);
+ }
+ return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::setHdrConversionStrategy(
+ const gui::HdrConversionStrategy& hdrConversionStrategy) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ status = mFlinger->setHdrConversionStrategy(hdrConversionStrategy);
+ }
+ return binderStatusFromStatusT(status);
+}
+
+binder::Status SurfaceComposerAIDL::getHdrOutputConversionSupport(bool* outMode) {
+ status_t status = checkAccessPermission();
+ if (status == OK) {
+ status = mFlinger->getHdrOutputConversionSupport(outMode);
+ }
+ return binderStatusFromStatusT(status);
+}
+
binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) {
status_t status = checkAccessPermission();
if (status != OK) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 064a1f1..33f0402 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -26,7 +26,6 @@
#include <android/gui/DisplayStatInfo.h>
#include <android/gui/DisplayState.h>
#include <android/gui/ISurfaceComposerClient.h>
-#include <android/gui/ITransactionCompletedListener.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <ftl/future.h>
@@ -35,8 +34,8 @@
#include <gui/CompositorTiming.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerDebugInfo.h>
-
#include <gui/LayerState.h>
#include <layerproto/LayerProtoHeader.h>
#include <math/mat4.h>
@@ -127,9 +126,7 @@
using gui::CaptureArgs;
using gui::DisplayCaptureArgs;
using gui::IRegionSamplingListener;
-using gui::ITransactionCompletedListener;
using gui::LayerCaptureArgs;
-
using gui::ScreenCaptureResults;
namespace frametimeline {
@@ -534,6 +531,10 @@
status_t setBootDisplayMode(const sp<display::DisplayToken>&, DisplayModeId);
status_t getOverlaySupport(gui::OverlayProperties* outProperties) const;
status_t clearBootDisplayMode(const sp<IBinder>& displayToken);
+ status_t getHdrConversionCapabilities(
+ std::vector<gui::HdrConversionCapability>* hdrConversionCapaabilities) const;
+ status_t setHdrConversionStrategy(const gui::HdrConversionStrategy& hdrConversionStrategy);
+ status_t getHdrOutputConversionSupport(bool* outSupport) const;
void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on);
void setGameContentType(const sp<IBinder>& displayToken, bool on);
void setPowerMode(const sp<IBinder>& displayToken, int mode);
@@ -1434,6 +1435,11 @@
binder::Status clearBootDisplayMode(const sp<IBinder>& display) override;
binder::Status getBootDisplayModeSupport(bool* outMode) override;
binder::Status getOverlaySupport(gui::OverlayProperties* outProperties) override;
+ binder::Status getHdrConversionCapabilities(
+ std::vector<gui::HdrConversionCapability>*) override;
+ binder::Status setHdrConversionStrategy(
+ const gui::HdrConversionStrategy& hdrConversionStrategy) override;
+ binder::Status getHdrOutputConversionSupport(bool* outSupport) override;
binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override;
binder::Status setGameContentType(const sp<IBinder>& display, bool on) override;
binder::Status captureDisplay(const DisplayCaptureArgs&,
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.h b/services/surfaceflinger/TransactionCallbackInvoker.h
index c09bcce..61ff9bc 100644
--- a/services/surfaceflinger/TransactionCallbackInvoker.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -26,27 +26,14 @@
#include <unordered_set>
#include <android-base/thread_annotations.h>
-#include <android/gui/ITransactionCompletedListener.h>
-
#include <binder/IBinder.h>
-#include <gui/ListenerStats.h>
-#include <gui/ReleaseCallbackId.h>
-#include <renderengine/RenderEngine.h>
+#include <ftl/future.h>
+#include <gui/ITransactionCompletedListener.h>
#include <ui/Fence.h>
#include <ui/FenceResult.h>
namespace android {
-using gui::CallbackId;
-using gui::FrameEventHistoryStats;
-using gui::IListenerHash;
-using gui::ITransactionCompletedListener;
-using gui::JankData;
-using gui::ListenerCallbacks;
-using gui::ListenerStats;
-using gui::ReleaseCallbackId;
-using gui::TransactionStats;
-
class CallbackHandle : public RefBase {
public:
CallbackHandle(const sp<IBinder>& transactionListener, const std::vector<CallbackId>& ids,
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
index 225ad16..ac5e927 100644
--- a/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetDisplayBrightnessTest.cpp
@@ -96,5 +96,23 @@
EXPECT_EQ(std::nullopt, displayDevice->getCompositionDisplay()->getState().displayBrightness);
}
+TEST_F(SetDisplayBrightnessTest, firstDisplayBrightnessWithComposite) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ sp<DisplayDevice> displayDevice = getDisplayDevice();
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+
+ constexpr float kDisplayBrightness = -1.0f;
+ displayDevice->stageBrightness(kDisplayBrightness);
+
+ EXPECT_EQ(-1.0f, displayDevice->getStagedBrightness());
+
+ displayDevice->persistBrightness(true);
+
+ EXPECT_EQ(std::nullopt, displayDevice->getStagedBrightness());
+ EXPECT_EQ(kDisplayBrightness,
+ displayDevice->getCompositionDisplay()->getState().displayBrightness);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 8f89a8c..afbc57a 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -147,6 +147,7 @@
}),
Return(hardware::graphics::composer::V2_4::Error::NONE)));
EXPECT_CALL(*mHal, getOverlaySupport(_)).WillOnce(Return(HalError::NONE));
+ EXPECT_CALL(*mHal, getHdrConversionCapabilities(_)).WillOnce(Return(HalError::NONE));
EXPECT_CALL(*mHal, registerCallback(_));
@@ -165,6 +166,7 @@
EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
.WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
EXPECT_CALL(*mHal, getOverlaySupport(_)).WillOnce(Return(HalError::UNSUPPORTED));
+ EXPECT_CALL(*mHal, getHdrConversionCapabilities(_)).WillOnce(Return(HalError::UNSUPPORTED));
EXPECT_CALL(*mHal, registerCallback(_));
mHwc.setCallback(mCallback);
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 2f16b7b..5e29fe7 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -145,6 +145,11 @@
MOCK_METHOD2(setBootDisplayConfig, Error(Display, Config));
MOCK_METHOD1(clearBootDisplayConfig, Error(Display));
MOCK_METHOD2(getPreferredBootDisplayConfig, Error(Display, Config*));
+ MOCK_METHOD1(getHdrConversionCapabilities,
+ Error(std::vector<
+ aidl::android::hardware::graphics::common::HdrConversionCapability>*));
+ MOCK_METHOD1(setHdrConversionStrategy,
+ Error(aidl::android::hardware::graphics::common::HdrConversionStrategy));
MOCK_METHOD2(getSupportedContentTypes,
V2_4::Error(Display, std::vector<IComposerClient::ContentType>*));
MOCK_METHOD2(setContentType, V2_4::Error(Display, IComposerClient::ContentType));