1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "InputTarget.h"
18 
19 #include <android-base/logging.h>
20 #include <android-base/stringprintf.h>
21 #include <input/PrintTools.h>
22 #include <inttypes.h>
23 #include <string>
24 
25 using android::base::Error;
26 using android::base::Result;
27 using android::base::StringPrintf;
28 
29 namespace android::inputdispatcher {
30 
31 namespace {
32 
33 const static ui::Transform kIdentityTransform{};
34 
35 }
36 
InputTarget(const std::shared_ptr<Connection> & connection,ftl::Flags<Flags> flags)37 InputTarget::InputTarget(const std::shared_ptr<Connection>& connection, ftl::Flags<Flags> flags)
38       : connection(connection), flags(flags) {}
39 
addPointers(std::bitset<MAX_POINTER_ID+1> newPointerIds,const ui::Transform & transform)40 Result<void> InputTarget::addPointers(std::bitset<MAX_POINTER_ID + 1> newPointerIds,
41                                       const ui::Transform& transform) {
42     // The pointerIds can be empty, but still a valid InputTarget. This can happen when there is no
43     // valid pointer property from the input event.
44     if (newPointerIds.none()) {
45         setDefaultPointerTransform(transform);
46         return {};
47     }
48 
49     // Ensure that the new set of pointers doesn't overlap with the current set of pointers.
50     if ((getPointerIds() & newPointerIds).any()) {
51         return Error() << __func__ << " - overlap with incoming pointers "
52                        << bitsetToString(newPointerIds) << " in " << *this;
53     }
54 
55     for (auto& [existingTransform, existingPointers] : mPointerTransforms) {
56         if (transform == existingTransform) {
57             existingPointers |= newPointerIds;
58             return {};
59         }
60     }
61     mPointerTransforms.emplace_back(transform, newPointerIds);
62     return {};
63 }
64 
setDefaultPointerTransform(const ui::Transform & transform)65 void InputTarget::setDefaultPointerTransform(const ui::Transform& transform) {
66     mPointerTransforms = {{transform, {}}};
67 }
68 
useDefaultPointerTransform() const69 bool InputTarget::useDefaultPointerTransform() const {
70     return mPointerTransforms.size() <= 1;
71 }
72 
getDefaultPointerTransform() const73 const ui::Transform& InputTarget::getDefaultPointerTransform() const {
74     if (!useDefaultPointerTransform()) {
75         LOG(FATAL) << __func__ << ": Not using default pointer transform";
76     }
77     return mPointerTransforms.size() == 1 ? mPointerTransforms[0].first : kIdentityTransform;
78 }
79 
getTransformForPointer(int32_t pointerId) const80 const ui::Transform& InputTarget::getTransformForPointer(int32_t pointerId) const {
81     for (const auto& [transform, ids] : mPointerTransforms) {
82         if (ids.test(pointerId)) {
83             return transform;
84         }
85     }
86 
87     LOG(FATAL) << __func__
88                << ": Cannot get transform: The following Pointer ID does not exist in target: "
89                << pointerId;
90     return kIdentityTransform;
91 }
92 
getPointerInfoString() const93 std::string InputTarget::getPointerInfoString() const {
94     std::string out = "\n";
95     if (useDefaultPointerTransform()) {
96         const ui::Transform& transform = getDefaultPointerTransform();
97         transform.dump(out, "default", "        ");
98         return out;
99     }
100 
101     for (const auto& [transform, ids] : mPointerTransforms) {
102         const std::string name = "pointerIds " + bitsetToString(ids) + ":";
103         transform.dump(out, name.c_str(), "        ");
104     }
105     return out;
106 }
107 
getPointerIds() const108 std::bitset<MAX_POINTER_ID + 1> InputTarget::getPointerIds() const {
109     PointerIds allIds;
110     for (const auto& [_, ids] : mPointerTransforms) {
111         allIds |= ids;
112     }
113     return allIds;
114 }
115 
operator <<(std::ostream & out,const InputTarget & target)116 std::ostream& operator<<(std::ostream& out, const InputTarget& target) {
117     out << "{connection=";
118     if (target.connection != nullptr) {
119         out << target.connection->getInputChannelName();
120     } else {
121         out << "<null>";
122     }
123     out << ", windowHandle=";
124     if (target.windowHandle != nullptr) {
125         out << target.windowHandle->getName();
126     } else {
127         out << "<null>";
128     }
129     out << ", dispatchMode=" << ftl::enum_string(target.dispatchMode).c_str();
130     out << ", targetFlags=" << target.flags.string();
131     out << ", pointers=" << target.getPointerInfoString();
132     out << "}";
133     return out;
134 }
135 
136 } // namespace android::inputdispatcher
137