1 /*
2  * Copyright (C) 2011 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 #define LOG_TAG "WindowInfo"
18 #define LOG_NDEBUG 0
19 
20 #include <type_traits>
21 
22 #include <binder/Parcel.h>
23 #include <gui/WindowInfo.h>
24 
25 #include <log/log.h>
26 
27 namespace android::gui {
28 
29 namespace {
30 
operator <<(std::ostream & out,const sp<IBinder> & binder)31 std::ostream& operator<<(std::ostream& out, const sp<IBinder>& binder) {
32     if (binder == nullptr) {
33         out << "<null>";
34     } else {
35         out << binder.get();
36     }
37     return out;
38 }
39 
operator <<(std::ostream & out,const Region & region)40 std::ostream& operator<<(std::ostream& out, const Region& region) {
41     if (region.isEmpty()) {
42         out << "<empty>";
43         return out;
44     }
45 
46     bool first = true;
47     Region::const_iterator cur = region.begin();
48     Region::const_iterator const tail = region.end();
49     while (cur != tail) {
50         if (first) {
51             first = false;
52         } else {
53             out << "|";
54         }
55         out << "[" << cur->left << "," << cur->top << "][" << cur->right << "," << cur->bottom
56             << "]";
57         cur++;
58     }
59     return out;
60 }
61 
62 } // namespace
63 
setInputConfig(ftl::Flags<InputConfig> config,bool value)64 void WindowInfo::setInputConfig(ftl::Flags<InputConfig> config, bool value) {
65     if (value) {
66         inputConfig |= config;
67         return;
68     }
69     inputConfig &= ~config;
70 }
71 
addTouchableRegion(const Rect & region)72 void WindowInfo::addTouchableRegion(const Rect& region) {
73     touchableRegion.orSelf(region);
74 }
75 
supportsSplitTouch() const76 bool WindowInfo::supportsSplitTouch() const {
77     return !inputConfig.test(InputConfig::PREVENT_SPLITTING);
78 }
79 
isSpy() const80 bool WindowInfo::isSpy() const {
81     return inputConfig.test(InputConfig::SPY);
82 }
83 
interceptsStylus() const84 bool WindowInfo::interceptsStylus() const {
85     return inputConfig.test(InputConfig::INTERCEPTS_STYLUS);
86 }
87 
overlaps(const WindowInfo * other) const88 bool WindowInfo::overlaps(const WindowInfo* other) const {
89     return !frame.isEmpty() && frame.left < other->frame.right && frame.right > other->frame.left &&
90             frame.top < other->frame.bottom && frame.bottom > other->frame.top;
91 }
92 
operator ==(const WindowInfo & info) const93 bool WindowInfo::operator==(const WindowInfo& info) const {
94     return info.token == token && info.id == id && info.name == name &&
95             info.dispatchingTimeout == dispatchingTimeout && info.frame == frame &&
96             info.contentSize == contentSize && info.surfaceInset == surfaceInset &&
97             info.globalScaleFactor == globalScaleFactor && info.transform == transform &&
98             info.touchableRegion.hasSameRects(touchableRegion) &&
99             info.touchOcclusionMode == touchOcclusionMode && info.ownerPid == ownerPid &&
100             info.ownerUid == ownerUid && info.packageName == packageName &&
101             info.inputConfig == inputConfig && info.displayId == displayId &&
102             info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop &&
103             info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType &&
104             info.layoutParamsFlags == layoutParamsFlags &&
105             info.canOccludePresentation == canOccludePresentation;
106 }
107 
writeToParcel(android::Parcel * parcel) const108 status_t WindowInfo::writeToParcel(android::Parcel* parcel) const {
109     if (parcel == nullptr) {
110         ALOGE("%s: Null parcel", __func__);
111         return BAD_VALUE;
112     }
113     if (name.empty()) {
114         parcel->writeInt32(0);
115         return OK;
116     }
117     parcel->writeInt32(1);
118 
119     // Ensure that the size of custom types are what we expect for writing into the parcel.
120     static_assert(sizeof(inputConfig) == 4u);
121     static_assert(sizeof(ownerPid.val()) == 4u);
122     static_assert(sizeof(ownerUid.val()) == 4u);
123 
124     // clang-format off
125     status_t status = parcel->writeStrongBinder(token) ?:
126         parcel->writeInt64(dispatchingTimeout.count()) ?:
127         parcel->writeInt32(id) ?:
128         parcel->writeUtf8AsUtf16(name) ?:
129         parcel->writeInt32(layoutParamsFlags.get()) ?:
130         parcel->writeInt32(
131                 static_cast<std::underlying_type_t<WindowInfo::Type>>(layoutParamsType)) ?:
132         parcel->write(frame) ?:
133         parcel->writeInt32(contentSize.width) ?:
134         parcel->writeInt32(contentSize.height) ?:
135         parcel->writeInt32(surfaceInset) ?:
136         parcel->writeFloat(globalScaleFactor) ?:
137         parcel->writeFloat(alpha) ?:
138         parcel->writeFloat(transform.dsdx()) ?:
139         parcel->writeFloat(transform.dtdx()) ?:
140         parcel->writeFloat(transform.tx()) ?:
141         parcel->writeFloat(transform.dtdy()) ?:
142         parcel->writeFloat(transform.dsdy()) ?:
143         parcel->writeFloat(transform.ty()) ?:
144         parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?:
145         parcel->writeInt32(ownerPid.val()) ?:
146         parcel->writeInt32(ownerUid.val()) ?:
147         parcel->writeUtf8AsUtf16(packageName) ?:
148         parcel->writeInt32(inputConfig.get()) ?:
149         parcel->writeInt32(displayId.val()) ?:
150         applicationInfo.writeToParcel(parcel) ?:
151         parcel->write(touchableRegion) ?:
152         parcel->writeBool(replaceTouchableRegionWithCrop) ?:
153         parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?:
154         parcel->writeStrongBinder(windowToken) ?:
155         parcel->writeStrongBinder(focusTransferTarget) ?:
156         parcel->writeBool(canOccludePresentation);
157     // clang-format on
158     return status;
159 }
160 
readFromParcel(const android::Parcel * parcel)161 status_t WindowInfo::readFromParcel(const android::Parcel* parcel) {
162     if (parcel == nullptr) {
163         ALOGE("%s: Null parcel", __func__);
164         return BAD_VALUE;
165     }
166     if (parcel->readInt32() == 0) {
167         return OK;
168     }
169 
170     token = parcel->readStrongBinder();
171     dispatchingTimeout = static_cast<decltype(dispatchingTimeout)>(parcel->readInt64());
172     status_t status = parcel->readInt32(&id) ?: parcel->readUtf8FromUtf16(&name);
173     if (status != OK) {
174         return status;
175     }
176 
177     float dsdx, dtdx, tx, dtdy, dsdy, ty;
178     int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt, ownerPidInt, ownerUidInt,
179             displayIdInt;
180     sp<IBinder> touchableRegionCropHandleSp;
181 
182     // clang-format off
183     status = parcel->readInt32(&lpFlags) ?:
184         parcel->readInt32(&lpType) ?:
185         parcel->read(frame) ?:
186         parcel->readInt32(&contentSize.width) ?:
187         parcel->readInt32(&contentSize.height) ?:
188         parcel->readInt32(&surfaceInset) ?:
189         parcel->readFloat(&globalScaleFactor) ?:
190         parcel->readFloat(&alpha) ?:
191         parcel->readFloat(&dsdx) ?:
192         parcel->readFloat(&dtdx) ?:
193         parcel->readFloat(&tx) ?:
194         parcel->readFloat(&dtdy) ?:
195         parcel->readFloat(&dsdy) ?:
196         parcel->readFloat(&ty) ?:
197         parcel->readInt32(&touchOcclusionModeInt) ?:
198         parcel->readInt32(&ownerPidInt) ?:
199         parcel->readInt32(&ownerUidInt) ?:
200         parcel->readUtf8FromUtf16(&packageName) ?:
201         parcel->readInt32(&inputConfigInt) ?:
202         parcel->readInt32(&displayIdInt) ?:
203         applicationInfo.readFromParcel(parcel) ?:
204         parcel->read(touchableRegion) ?:
205         parcel->readBool(&replaceTouchableRegionWithCrop) ?:
206         parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?:
207         parcel->readNullableStrongBinder(&windowToken) ?:
208         parcel->readNullableStrongBinder(&focusTransferTarget) ?:
209         parcel->readBool(&canOccludePresentation);
210 
211     // clang-format on
212 
213     if (status != OK) {
214         return status;
215     }
216 
217     layoutParamsFlags = ftl::Flags<Flag>(lpFlags);
218     layoutParamsType = static_cast<Type>(lpType);
219     transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
220     touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
221     inputConfig = ftl::Flags<InputConfig>(inputConfigInt);
222     ownerPid = Pid{ownerPidInt};
223     ownerUid = Uid{static_cast<uid_t>(ownerUidInt)};
224     touchableRegionCropHandle = touchableRegionCropHandleSp;
225     displayId = ui::LogicalDisplayId{displayIdInt};
226 
227     return OK;
228 }
229 
WindowInfoHandle()230 WindowInfoHandle::WindowInfoHandle() {}
231 
~WindowInfoHandle()232 WindowInfoHandle::~WindowInfoHandle() {}
233 
WindowInfoHandle(const WindowInfoHandle & other)234 WindowInfoHandle::WindowInfoHandle(const WindowInfoHandle& other) : mInfo(other.mInfo) {}
235 
WindowInfoHandle(const WindowInfo & other)236 WindowInfoHandle::WindowInfoHandle(const WindowInfo& other) : mInfo(other) {}
237 
writeToParcel(android::Parcel * parcel) const238 status_t WindowInfoHandle::writeToParcel(android::Parcel* parcel) const {
239     return mInfo.writeToParcel(parcel);
240 }
241 
readFromParcel(const android::Parcel * parcel)242 status_t WindowInfoHandle::readFromParcel(const android::Parcel* parcel) {
243     return mInfo.readFromParcel(parcel);
244 }
245 
releaseChannel()246 void WindowInfoHandle::releaseChannel() {
247     mInfo.token.clear();
248 }
249 
getToken() const250 sp<IBinder> WindowInfoHandle::getToken() const {
251     return mInfo.token;
252 }
253 
updateFrom(sp<WindowInfoHandle> handle)254 void WindowInfoHandle::updateFrom(sp<WindowInfoHandle> handle) {
255     mInfo = handle->mInfo;
256 }
257 
operator <<(std::ostream & out,const WindowInfo & info)258 std::ostream& operator<<(std::ostream& out, const WindowInfo& info) {
259     out << "name=" << info.name << ", id=" << info.id << ", displayId=" << info.displayId
260         << ", inputConfig=" << info.inputConfig.string() << ", alpha=" << info.alpha << ", frame=["
261         << info.frame.left << "," << info.frame.top << "][" << info.frame.right << ","
262         << info.frame.bottom << "], globalScale=" << info.globalScaleFactor
263         << ", applicationInfo.name=" << info.applicationInfo.name
264         << ", applicationInfo.token=" << info.applicationInfo.token
265         << ", touchableRegion=" << info.touchableRegion << ", ownerPid=" << info.ownerPid.toString()
266         << ", ownerUid=" << info.ownerUid.toString() << ", dispatchingTimeout="
267         << std::chrono::duration_cast<std::chrono::milliseconds>(info.dispatchingTimeout).count()
268         << "ms, token=" << info.token.get()
269         << ", touchOcclusionMode=" << ftl::enum_string(info.touchOcclusionMode);
270     if (info.canOccludePresentation) out << ", canOccludePresentation";
271     std::string transform;
272     info.transform.dump(transform, "transform", "    ");
273     out << "\n" << transform;
274     return out;
275 }
276 
operator <<(std::ostream & out,const WindowInfoHandle & window)277 std::ostream& operator<<(std::ostream& out, const WindowInfoHandle& window) {
278     const WindowInfo& info = *window.getInfo();
279     out << info;
280     return out;
281 }
282 
283 } // namespace android::gui
284