Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 12b896f4 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11585034 from 531219a8 to 24Q3-release

Change-Id: I4350c2d93f28ae60c1a8a3deff9046e792b414d8
parents 3de51b38 531219a8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -236,6 +236,10 @@ void ASurfaceTransactionStats_releaseASurfaceControls(ASurfaceControl** surface_
 * it is acquired. If no acquire_fence_fd was provided, this timestamp will be set to -1.
 *
 * Available since API level 29.
 *
 * @deprecated This may return SIGNAL_PENDING because the stats can arrive before the acquire
 * fence has signaled, depending on internal timing differences. Therefore the caller should
 * use the acquire fence passed in to setBuffer and query the signal time.
 */
int64_t ASurfaceTransactionStats_getAcquireTime(ASurfaceTransactionStats* surface_transaction_stats,
                                                ASurfaceControl* surface_control)
+211 −0
Original line number Diff line number Diff line
/**
 * Copyright 2024 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 <utils/Looper.h>
#include "InputTransport.h"

namespace android {

/**
 * An interface to receive batched input events. Even if you don't want batching, you still have to
 * use this interface, and some of the events will be batched if your implementation is slow to
 * handle the incoming input.
 */
class InputConsumerCallbacks {
public:
    virtual ~InputConsumerCallbacks(){};
    virtual void onKeyEvent(KeyEvent&& event, uint32_t seq) = 0;
    virtual void onMotionEvent(MotionEvent&& event, uint32_t seq) = 0;
    /**
     * When you receive this callback, you must (eventually) call "consumeBatchedInputEvents".
     * If you don't want batching, then call "consumeBatchedInputEvents" immediately with
     * std::nullopt frameTime to receive the pending motion event(s).
     * @param pendingBatchSource the source of the pending batch.
     */
    virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0;
    virtual void onFocusEvent(FocusEvent&& event, uint32_t seq) = 0;
    virtual void onCaptureEvent(CaptureEvent&& event, uint32_t seq) = 0;
    virtual void onDragEvent(DragEvent&& event, uint32_t seq) = 0;
    virtual void onTouchModeEvent(TouchModeEvent&& event, uint32_t seq) = 0;
};

/**
 * Consumes input events from an input channel.
 *
 * This is a re-implementation of InputConsumer that does not have resampling at the current moment.
 * A lot of the higher-level logic has been folded into this class, to make it easier to use.
 * In the legacy class, InputConsumer, the consumption logic was partially handled in the jni layer,
 * as well as various actions like adding the fd to the Choreographer.
 *
 * TODO(b/297226446): use this instead of "InputConsumer":
 * - Add resampling to this class
 * - Allow various resampling strategies to be specified
 * - Delete the old "InputConsumer" and use this class instead, renaming it to "InputConsumer".
 * - Add tracing
 * - Update all tests to use the new InputConsumer
 *
 * This class is not thread-safe. We are currently allowing the constructor to run on any thread,
 * but all of the remaining APIs should be invoked on the looper thread only.
 */
class InputConsumerNoResampling final {
public:
    explicit InputConsumerNoResampling(const std::shared_ptr<InputChannel>& channel,
                                       sp<Looper> looper, InputConsumerCallbacks& callbacks);
    ~InputConsumerNoResampling();

    /**
     * Must be called exactly once for each event received through the callbacks.
     */
    void finishInputEvent(uint32_t seq, bool handled);
    void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime);
    /**
     * If you want to consume all events immediately (disable batching), the you still must call
     * this. For frameTime, use a std::nullopt.
     * @param frameTime the time up to which consume the events. When there's double (or triple)
     * buffering, you may want to not consume all events currently available, because you could be
     * still working on an older frame, but there could already have been events that arrived that
     * are more recent.
     * @return whether any events were actually consumed
     */
    bool consumeBatchedInputEvents(std::optional<nsecs_t> frameTime);
    /**
     * Returns true when there is *likely* a pending batch or a pending event in the channel.
     *
     * This is only a performance hint and may return false negative results. Clients should not
     * rely on availability of the message based on the return value.
     */
    bool probablyHasInput() const;

    std::string getName() { return mChannel->getName(); }

    std::string dump() const;

private:
    std::shared_ptr<InputChannel> mChannel;
    sp<Looper> mLooper;
    InputConsumerCallbacks& mCallbacks;

    // Looper-related infrastructure
    /**
     * This class is needed to associate the function "handleReceiveCallback" with the provided
     * looper. The callback sent to the looper is RefBase - based, so we can't just send a reference
     * of this class directly to the looper.
     */
    class LooperEventCallback : public LooperCallback {
    public:
        LooperEventCallback(std::function<int(int events)> callback) : mCallback(callback) {}
        int handleEvent(int /*fd*/, int events, void* /*data*/) override {
            return mCallback(events);
        }

    private:
        std::function<int(int events)> mCallback;
    };
    sp<LooperEventCallback> mCallback;
    /**
     * The actual code that executes when the looper encounters available data on the InputChannel.
     */
    int handleReceiveCallback(int events);
    int mFdEvents;
    void setFdEvents(int events);

    void ensureCalledOnLooperThread(const char* func) const;

    // Event-reading infrastructure
    /**
     * A fifo queue of events to be sent to the InputChannel. We can't send all InputMessages to
     * the channel immediately when they are produced, because it's possible that the InputChannel
     * is blocked (if the channel buffer is full). When that happens, we don't want to drop the
     * events. Therefore, events should only be erased from the queue after they've been
     * successfully written to the InputChannel.
     */
    std::queue<InputMessage> mOutboundQueue;
    /**
     * Try to send all of the events in mOutboundQueue over the InputChannel. Not all events might
     * actually get sent, because it's possible that the channel is blocked.
     */
    void processOutboundEvents();

    /**
     * The time at which each event with the sequence number 'seq' was consumed.
     * This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
     * This collection is populated when the event is received, and the entries are erased when the
     * events are finished. It should not grow infinitely because if an event is not ack'd, ANR
     * will be raised for that connection, and no further events will be posted to that channel.
     */
    std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
    /**
     * Find and return the consumeTime associated with the provided sequence number. Crashes if
     * the provided seq number is not found.
     */
    nsecs_t popConsumeTime(uint32_t seq);

    // Event reading and processing
    /**
     * Read all of the available events from the InputChannel
     */
    std::vector<InputMessage> readAllMessages();

    /**
     * Send InputMessage to the corresponding InputConsumerCallbacks function.
     * @param msg
     */
    void handleMessage(const InputMessage& msg) const;

    // Batching
    /**
     * Batch messages that can be batched. When an unbatchable message is encountered, send it
     * to the InputConsumerCallbacks immediately. If there are batches remaining,
     * notify InputConsumerCallbacks.
     */
    void handleMessages(std::vector<InputMessage>&& messages);
    /**
     * Batched InputMessages, per deviceId.
     * For each device, we are storing a queue of batched messages. These will all be collapsed into
     * a single MotionEvent (up to a specific frameTime) when the consumer calls
     * `consumeBatchedInputEvents`.
     */
    std::map<DeviceId, std::queue<InputMessage>> mBatches;
    /**
     * A map from a single sequence number to several sequence numbers. This is needed because of
     * batching. When batching is enabled, a single MotionEvent will contain several samples. Each
     * sample came from an individual InputMessage of Type::Motion, and therefore will have to be
     * finished individually. Therefore, when the app calls "finish" on a (possibly batched)
     * MotionEvent, we will need to check this map in case there are multiple sequence numbers
     * associated with a single number that the app provided.
     *
     * For example:
     * Suppose we received 4 InputMessage's of type Motion, with action MOVE:
     * InputMessage(MOVE)   InputMessage(MOVE)   InputMessage(MOVE)   InputMessage(MOVE)
     *    seq=10               seq=11               seq=12               seq=13
     * The app consumed them all as a batch, which means that the app received a single MotionEvent
     * with historySize=3 and seq = 10.
     *
     * This map will look like:
     * {
     *   10: [11, 12, 13],
     * }
     * So the sequence number 10 will have 3 other sequence numbers associated with it.
     * When the app calls 'finish' for seq=10, we need to call 'finish' 4 times total, for sequence
     * numbers 10, 11, 12, 13. The app is not aware of the sequence numbers of each sample inside
     * the batched MotionEvent that it received.
     */
    std::map<uint32_t, std::vector<uint32_t>> mBatchedSequenceNumbers;
};

} // namespace android
+3 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ cc_library {

    llndk: {
        symbol_file: "libbinder_ndk.map.txt",
        export_llndk_headers: ["libvendorsupport_llndk_headers"],
    },

    export_include_dirs: [
@@ -79,9 +80,11 @@ cc_library {
    ],

    header_libs: [
        "libvendorsupport_llndk_headers",
        "jni_headers",
    ],
    export_header_lib_headers: [
        "libvendorsupport_llndk_headers",
        "jni_headers",
    ],

+51 −44
Original line number Diff line number Diff line
@@ -24,6 +24,13 @@

namespace aidl::android::os {

#if defined(__ANDROID_VENDOR__)
#define AT_LEAST_V_OR_202404 constexpr(__ANDROID_VENDOR_API__ >= 202404)
#else
// TODO(b/322384429) switch this to __ANDROID_API_V__ when V is finalized
#define AT_LEAST_V_OR_202404 (__builtin_available(android __ANDROID_API_FUTURE__, *))
#endif

/**
 * Wrapper class that enables interop with AIDL NDK generation
 * Takes ownership of the APersistableBundle* given to it in reset() and will automatically
@@ -32,7 +39,7 @@ namespace aidl::android::os {
class PersistableBundle {
   public:
    PersistableBundle() noexcept {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            mPBundle = APersistableBundle_new();
        }
    }
@@ -42,13 +49,13 @@ class PersistableBundle {
    PersistableBundle(PersistableBundle&& other) noexcept : mPBundle(other.release()) {}
    // duplicates, does not take ownership of the APersistableBundle*
    PersistableBundle(const PersistableBundle& other) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            mPBundle = APersistableBundle_dup(other.mPBundle);
        }
    }
    // duplicates, does not take ownership of the APersistableBundle*
    PersistableBundle& operator=(const PersistableBundle& other) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            mPBundle = APersistableBundle_dup(other.mPBundle);
        }
        return *this;
@@ -58,7 +65,7 @@ class PersistableBundle {

    binder_status_t readFromParcel(const AParcel* _Nonnull parcel) {
        reset();
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_readFromParcel(parcel, &mPBundle);
        } else {
            return STATUS_INVALID_OPERATION;
@@ -69,7 +76,7 @@ class PersistableBundle {
        if (!mPBundle) {
            return STATUS_BAD_VALUE;
        }
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_writeToParcel(mPBundle, parcel);
        } else {
            return STATUS_INVALID_OPERATION;
@@ -84,7 +91,7 @@ class PersistableBundle {
     */
    void reset(APersistableBundle* _Nullable pBundle = nullptr) noexcept {
        if (mPBundle) {
            if (__builtin_available(android __ANDROID_API_V__, *)) {
            if AT_LEAST_V_OR_202404 {
                APersistableBundle_delete(mPBundle);
            }
            mPBundle = nullptr;
@@ -97,7 +104,7 @@ class PersistableBundle {
     * what should be used to check for equality.
     */
    bool deepEquals(const PersistableBundle& rhs) const {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_isEqual(get(), rhs.get());
        } else {
            return false;
@@ -136,7 +143,7 @@ class PersistableBundle {
    inline std::string toString() const {
        if (!mPBundle) {
            return "<PersistableBundle: null>";
        } else if (__builtin_available(android __ANDROID_API_V__, *)) {
        } else if AT_LEAST_V_OR_202404 {
            std::ostringstream os;
            os << "<PersistableBundle: ";
            os << "size: " << std::to_string(APersistableBundle_size(mPBundle));
@@ -147,7 +154,7 @@ class PersistableBundle {
    }

    int32_t size() const {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_size(mPBundle);
        } else {
            return 0;
@@ -155,7 +162,7 @@ class PersistableBundle {
    }

    int32_t erase(const std::string& key) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_erase(mPBundle, key.c_str());
        } else {
            return 0;
@@ -163,37 +170,37 @@ class PersistableBundle {
    }

    void putBoolean(const std::string& key, bool val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle_putBoolean(mPBundle, key.c_str(), val);
        }
    }

    void putInt(const std::string& key, int32_t val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle_putInt(mPBundle, key.c_str(), val);
        }
    }

    void putLong(const std::string& key, int64_t val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle_putLong(mPBundle, key.c_str(), val);
        }
    }

    void putDouble(const std::string& key, double val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle_putDouble(mPBundle, key.c_str(), val);
        }
    }

    void putString(const std::string& key, const std::string& val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle_putString(mPBundle, key.c_str(), val.c_str());
        }
    }

    void putBooleanVector(const std::string& key, const std::vector<bool>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            // std::vector<bool> has no ::data().
            int32_t num = vec.size();
            if (num > 0) {
@@ -210,7 +217,7 @@ class PersistableBundle {
    }

    void putIntVector(const std::string& key, const std::vector<int32_t>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            int32_t num = vec.size();
            if (num > 0) {
                APersistableBundle_putIntVector(mPBundle, key.c_str(), vec.data(), num);
@@ -218,7 +225,7 @@ class PersistableBundle {
        }
    }
    void putLongVector(const std::string& key, const std::vector<int64_t>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            int32_t num = vec.size();
            if (num > 0) {
                APersistableBundle_putLongVector(mPBundle, key.c_str(), vec.data(), num);
@@ -226,7 +233,7 @@ class PersistableBundle {
        }
    }
    void putDoubleVector(const std::string& key, const std::vector<double>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            int32_t num = vec.size();
            if (num > 0) {
                APersistableBundle_putDoubleVector(mPBundle, key.c_str(), vec.data(), num);
@@ -234,7 +241,7 @@ class PersistableBundle {
        }
    }
    void putStringVector(const std::string& key, const std::vector<std::string>& vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            int32_t num = vec.size();
            if (num > 0) {
                char** inVec = (char**)malloc(num * sizeof(char*));
@@ -249,13 +256,13 @@ class PersistableBundle {
        }
    }
    void putPersistableBundle(const std::string& key, const PersistableBundle& pBundle) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle_putPersistableBundle(mPBundle, key.c_str(), pBundle.mPBundle);
        }
    }

    bool getBoolean(const std::string& key, bool* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_getBoolean(mPBundle, key.c_str(), val);
        } else {
            return false;
@@ -263,7 +270,7 @@ class PersistableBundle {
    }

    bool getInt(const std::string& key, int32_t* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_getInt(mPBundle, key.c_str(), val);
        } else {
            return false;
@@ -271,7 +278,7 @@ class PersistableBundle {
    }

    bool getLong(const std::string& key, int64_t* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_getLong(mPBundle, key.c_str(), val);
        } else {
            return false;
@@ -279,7 +286,7 @@ class PersistableBundle {
    }

    bool getDouble(const std::string& key, double* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return APersistableBundle_getDouble(mPBundle, key.c_str(), val);
        } else {
            return false;
@@ -291,7 +298,7 @@ class PersistableBundle {
    }

    bool getString(const std::string& key, std::string* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            char* outString = nullptr;
            bool ret = APersistableBundle_getString(mPBundle, key.c_str(), &outString,
                                                    &stringAllocator, nullptr);
@@ -309,7 +316,7 @@ class PersistableBundle {
                                                   const char* _Nonnull, T* _Nullable, int32_t),
                        const APersistableBundle* _Nonnull pBundle, const char* _Nonnull key,
                        std::vector<T>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            int32_t bytes = 0;
            // call first with nullptr to get required size in bytes
            bytes = getVec(pBundle, key, nullptr, 0);
@@ -331,28 +338,28 @@ class PersistableBundle {
    }

    bool getBooleanVector(const std::string& key, std::vector<bool>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getVecInternal<bool>(&APersistableBundle_getBooleanVector, mPBundle, key.c_str(),
                                        vec);
        }
        return false;
    }
    bool getIntVector(const std::string& key, std::vector<int32_t>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getVecInternal<int32_t>(&APersistableBundle_getIntVector, mPBundle, key.c_str(),
                                           vec);
        }
        return false;
    }
    bool getLongVector(const std::string& key, std::vector<int64_t>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getVecInternal<int64_t>(&APersistableBundle_getLongVector, mPBundle, key.c_str(),
                                           vec);
        }
        return false;
    }
    bool getDoubleVector(const std::string& key, std::vector<double>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getVecInternal<double>(&APersistableBundle_getDoubleVector, mPBundle,
                                          key.c_str(), vec);
        }
@@ -377,7 +384,7 @@ class PersistableBundle {
    }

    bool getStringVector(const std::string& key, std::vector<std::string>* _Nonnull vec) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            int32_t bytes = APersistableBundle_getStringVector(mPBundle, key.c_str(), nullptr, 0,
                                                               &stringAllocator, nullptr);
            if (bytes > 0) {
@@ -394,7 +401,7 @@ class PersistableBundle {
    }

    bool getPersistableBundle(const std::string& key, PersistableBundle* _Nonnull val) {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            APersistableBundle* bundle = nullptr;
            bool ret = APersistableBundle_getPersistableBundle(mPBundle, key.c_str(), &bundle);
            if (ret) {
@@ -426,77 +433,77 @@ class PersistableBundle {
    }

    std::set<std::string> getBooleanKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getBooleanKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getIntKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getIntKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getLongKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getLongKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getDoubleKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getDoubleKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getStringKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getStringKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getBooleanVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getBooleanVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getIntVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getIntVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getLongVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getLongVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getDoubleVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getDoubleVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getStringVectorKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getStringVectorKeys, mPBundle);
        } else {
            return {};
        }
    }
    std::set<std::string> getPersistableBundleKeys() {
        if (__builtin_available(android __ANDROID_API_V__, *)) {
        if AT_LEAST_V_OR_202404 {
            return getKeys(&APersistableBundle_getPersistableBundleKeys, mPBundle);
        } else {
            return {};
+88 −69

File changed.

Preview size limit exceeded, changes collapsed.

Loading