当前位置: 首页 > news >正文

企业建站报价设计师常用网站门户

企业建站报价,设计师常用网站门户,公司简介模板500字,中国icp备案的有多少企业网站1. 多指触控协议 多指触控协议有 2 种#xff1a; A类#xff1a; 处理无关联的接触#xff1a; 用于直接发送原始数据#xff1b; B类#xff1a; 处理跟踪识别类的接触#xff1a; 通过事件slot发送相关联的独立接触更新。 B协议可以使用一个ID来标识触点 A类 处理无关联的接触 用于直接发送原始数据  B类 处理跟踪识别类的接触 通过事件slot发送相关联的独立接触更新。 B协议可以使用一个ID来标识触点可以减少上报到用户空间的数据量这个IDABS_MT_TRACKING_ID可以有硬件提供或者从原始数据计算而得。而InputReader 就是处理这些数据 通过下列命令可以dump adb shell getevent -tl [    1029.903648] /dev/input/event1: EV_SYN       0004                 00000405             [    1029.903648] /dev/input/event1: EV_SYN       0005                 35c02ec5             [    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000000            [    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_POSITION_X    00000173             第一个手指X坐标 [    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000001             [    1029.903648] /dev/input/event1: EV_ABS       ABS_MT_POSITION_X    00000321             第二个手指X坐标 [    1029.903648] /dev/input/event1: EV_SYN       SYN_REPORT           00000000             [    1031.902947] /dev/input/event1: EV_SYN       0004                 00000407             [    1031.902947] /dev/input/event1: EV_SYN       0005                 35b8a020             [    1031.902947] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000000            第一个手指有事件  [    1031.902947] /dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   ffffffff            TRACKING_ID为-1代表第一个手指抬起消失 [    1031.902947] /dev/input/event1: EV_SYN       SYN_REPORT           00000000              [    1032.024946] /dev/input/event1: EV_SYN       0004                 00000408             [    1032.024946] /dev/input/event1: EV_SYN       0005                 016372d8             [    1032.024946] /dev/input/event1: EV_ABS       ABS_MT_SLOT          00000001            第二个手指有事件   [    1032.024946] /dev/input/event1: EV_ABS       ABS_MT_POSITION_Y    0000016c              第二个 Y坐标 [    1032.024946] /dev/input/event1: EV_SYN       SYN_REPORT           00000000              [    1032.907686] /dev/input/event1: EV_SYN       0004                 00000408             [    1032.907686] /dev/input/event1: EV_SYN       0005                 35ebac8c             [    1032.907686] /dev/input/event1: EV_ABS       ABS_MT_TRACKING_ID   ffffffff            第二个手指消失抬起   [    1032.907686] /dev/input/event1: EV_KEY       BTN_TOUCH            UP                  抬起 [    1032.907686] /dev/input/event1: EV_KEY       BTN_TOOL_FINGER      UP                   [    1032.907686] /dev/input/event1: EV_SYN       SYN_REPORT           00000000   其中分为 3 个类型为 EV_SYN、EV_ABS 和 EV_KEY 0004代表一个事件开始不必要 0005代表一个事件开始不必要 SYN_REPORT代表一个事件的结束 必要 ABS_MT_SLOT 本质代表者不同手指它的value代表手指id  ABS_MT_TRACKING_ID 类型B特有的实际上每个slot会和一个ID相对应一个非负数的表示一次接触-1表示这是一个无用的slot或者理解为一次接触的结束 。 BTN_TOUCH 触碰按键。其值是DOWN或者UP。 2. InputReader 处理触摸数据 /frameworks/native/services/inputflinger/reader/InputReader.cpp InputReader 监听设备的数据getEvents()是阻塞的只有当有事件或者被wake才会被唤醒向下执行。 86 void InputReader::loopOnce() { 87 int32_t oldGeneration; 88 int32_t timeoutMillis; 89 bool inputDevicesChanged false; 90 std::vectorInputDeviceInfo inputDevices; 91 { // acquire lock 92 std::scoped_lock _l(mLock); 93 94 oldGeneration mGeneration; 95 timeoutMillis -1; 96 。。。。。 107 // 1从eventhub 中获取驱动上报的事件 getEvents 108 size_t count mEventHub-getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); 109 110 { // acquire lock 111 std::scoped_lock _l(mLock); 112 mReaderIsAliveCondition.notify_all(); 113 114 if (count) { // 2处理上报的数据processEventsLocked 115 processEventsLocked(mEventBuffer, count); 116 } 117 。。。。 // 3观察者队列去flush处理全部的事件flush 147 mQueuedListener-flush(); 148 } // 1从eventhub 中获取驱动上报的事件 getEvents 1461 size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { 1462 ALOG_ASSERT(bufferSize 1); 1463 1464 std::scoped_lock _l(mLock); 1465 1466 struct input_event readBuffer[bufferSize]; 1467 1468 RawEvent* event buffer; 1469 size_t capacity bufferSize; 1470 bool awoken false; 1471 for (;;) { 1472 nsecs_t now systemTime(SYSTEM_TIME_MONOTONIC);。。。。。。 1548 // Grab the next input event. 1549 bool deviceChanged false;// 设置 mPendingEventCount 值则满足下列条件 1550 while (mPendingEventIndex mPendingEventCount) { 1551 const struct epoll_event eventItem mPendingEventItems[mPendingEventIndex];// 通过fd 获取到对应的 Device创建对象为 std::make_uniqueDevice(fd 1577 Device* device getDeviceByFdLocked(eventItem.data.fd);1605 if (eventItem.events EPOLLIN) { // 读取对应fd 的数据 1606 int32_t readSize 1607 read(device-fd, readBuffer, sizeof(struct input_event) * capacity);。。。。。 1621 } else { 1622 int32_t deviceId device-id mBuiltInKeyboardId ? 0 : device-id; 1623 1624 size_t count size_t(readSize) / sizeof(struct input_event); 1625 for (size_t i 0; i count; i) { 1626 struct input_event iev readBuffer[i]; 1627 event-when processEventTimestamp(iev); 1628 event-readTime systemTime(SYSTEM_TIME_MONOTONIC); 1629 event-deviceId deviceId; // 将上报的type 和 code value 保存到 event 中遍历所有然后退出 1630 event-type iev.type; 1631 event-code iev.code; 1632 event-value iev.value; 1633 event 1; 1634 capacity - 1; 1635 } 1636 if (capacity 0) { 1637 // The result buffer is full. Reset the pending event index 1638 // so we will try to read the device again on the next iteration. 1639 mPendingEventIndex - 1; 1640 break; 1641 } 1642 } 。。。。。。 // 首先是epoll 监听底层的事件 1688 int pollResult epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); 1689 1690 mLock.lock(); // reacquire lock after poll 。。。。。。。 1708 } else { 1709 // Some events occurred. // 如果有事件的话 设置 mPendingEventCount 值 1710 mPendingEventCount size_t(pollResult); 1711 } 1712 } 1713 1714 // All done, return the number of events we read. 1715 return event - buffer; 1716 } // 将上报的type 和 code value 保存到 event  中遍历所有然后return退出数据给到 processEventsLocked 处理。 // 2处理上报的数据processEventsLocked processEventsLocked()函数中会遍历所有的事件分别进行处理。其处理的事件类型分为四种原始输入事件、设备加载事件、设备卸载事件及FINISHED_DEVICE_SCAN事件。 /frameworks/native/services/inputflinger/reader/InputReader.cpp 150 void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {// 遍历处理所有的事件 rawEvent 151 for (const RawEvent* rawEvent rawEvents; count;) { 152 int32_t type rawEvent-type; 153 size_t batchSize 1; 154 if (type EventHubInterface::FIRST_SYNTHETIC_EVENT) { // 获取到设备的id 155 int32_t deviceId rawEvent-deviceId; 156 while (batchSize count) { 157 if (rawEvent[batchSize].type EventHubInterface::FIRST_SYNTHETIC_EVENT || 158 rawEvent[batchSize].deviceId ! deviceId) { 159 break; 160 } 161 batchSize 1; 162 } 163 #if DEBUG_RAW_EVENTS 164 ALOGD(BatchSize: %zu Count: %zu, batchSize, count); 165 #endif // 处理事件 processEventsForDeviceLocked 166 processEventsForDeviceLocked(deviceId, rawEvent, batchSize); 296 void InputReader::processEventsForDeviceLocked(int32_t eventHubId, const RawEvent* rawEvents, 297 size_t count) {// 通过hubid 找到对应的 InputDevice 298 auto deviceIt mDevices.find(eventHubId); 299 if (deviceIt mDevices.end()) { 300 ALOGW(Discarding event for unknown eventHubId %d., eventHubId); 301 return; 302 } 303 304 std::shared_ptrInputDevice device deviceIt-second; 305 if (device-isIgnored()) { 306 // ALOGD(Discarding event for ignored deviceId %d., deviceId); 307 return; 308 } 309 // 通过 InputDevice 去处理事件process 310 device-process(rawEvents, count); 311 } // 通过 InputDevice 去处理事件process。 根据事件获得相应的设备类型然后将事件交给相应的设备处理给触摸设备相关的类去处理。 /frameworks/native/services/inputflinger/reader/InputDevice.cpp 375 void InputDevice::process(const RawEvent* rawEvents, size_t count) {// 遍历所有的事件 381 for (const RawEvent* rawEvent rawEvents; count ! 0; rawEvent) { 382 #if DEBUG_RAW_EVENTS 383 ALOGD(Input event: device%d type0x%04x code0x%04x value0x%08x when% PRId64, 384 rawEvent-deviceId, rawEvent-type, rawEvent-code, rawEvent-value, rawEvent-when); 385 #endif 386 387 if (mDropUntilNextSync) { 388 if (rawEvent-type EV_SYN rawEvent-code SYN_REPORT) { 389 mDropUntilNextSync false; 390 #if DEBUG_RAW_EVENTS 391 ALOGD(Recovered from input event buffer overrun.); 392 #endif 393 } else { 394 #if DEBUG_RAW_EVENTS 395 ALOGD(Dropped input event while waiting for next input sync.); 396 #endif 397 } // 如果事件类型是 SYN_DROPPED则drop 这个事件 398 } else if (rawEvent-type EV_SYN rawEvent-code SYN_DROPPED) { 399 ALOGI(Detected input event buffer overrun for device %s., getName().c_str()); 400 mDropUntilNextSync true; 401 reset(rawEvent-when); 402 } else {// 遍历所有的mapper 去处理 rawevent 403 for_each_mapper_in_subdevice(rawEvent-deviceId, [rawEvent](InputMapper mapper) { 404 mapper.process(rawEvent); 405 }); 406 } 407 --count; 408 } 409 } // 遍历所有的mapper 去处理 rawevent // 前面 addEventubDevice 的时候将其MultiTouchInputMapper 增加到了mapper 中 195 inline void for_each_mapper_in_subdevice(int32_t eventHubDevice, 196 std::functionvoid(InputMapper) f) { 197 auto deviceIt mDevices.find(eventHubDevice); 198 if (deviceIt ! mDevices.end()) { 199 auto devicePair deviceIt-second; 200 auto mappers devicePair.second; 201 for (auto mapperPtr : mappers) { 202 f(*mapperPtr); 203 } 204 } 205 } 调用 MultiTouchInputMapper  的process 方法 /frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp 238 void MultiTouchInputMapper::process(const RawEvent* rawEvent) {// 2-1)TouchInputMapper 先进行处理 process 239 TouchInputMapper::process(rawEvent); 240 // 2-2MultiTouchMotionAccumulator 处理rawEventprocess 241 mMultiTouchMotionAccumulator.process(rawEvent); 242 } 其实是先处理process然后再去 // 2-2MultiTouchMotionAccumulator 处理rawEventprocess 通过 MultiTouchMotionAccumulator.process处理了 85 void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { 86 if (rawEvent-type EV_ABS) { 87 bool newSlot false; 。。。。。。。 105 } else {// mCurrentSlot 为当前的手指 106 Slot* slot mSlots[mCurrentSlot]; 107 // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of 108 // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while 109 // updating the slot. 110 if (!mUsingSlotsProtocol) { // 设置为true 111 slot-mInUse true; 112 } 113 114 switch (rawEvent-code) { // 设置对应的xy 轴值 115 case ABS_MT_POSITION_X: 116 slot-mAbsMTPositionX rawEvent-value; 117 warnIfNotInUse(*rawEvent, *slot); 118 break; 119 case ABS_MT_POSITION_Y: 120 slot-mAbsMTPositionY rawEvent-value; 121 warnIfNotInUse(*rawEvent, *slot); 122 break; 123 case ABS_MT_TOUCH_MAJOR: 124 slot-mAbsMTTouchMajor rawEvent-value; 125 break; 126 case ABS_MT_TOUCH_MINOR: 127 slot-mAbsMTTouchMinor rawEvent-value; 128 slot-mHaveAbsMTTouchMinor true; 129 break; 130 case ABS_MT_WIDTH_MAJOR: 131 slot-mAbsMTWidthMajor rawEvent-value; 132 break; 133 case ABS_MT_WIDTH_MINOR: 134 slot-mAbsMTWidthMinor rawEvent-value; 135 slot-mHaveAbsMTWidthMinor true; 136 break; 137 case ABS_MT_ORIENTATION: 138 slot-mAbsMTOrientation rawEvent-value; 139 break;// trackid 为手指数表示第几个手指 140 case ABS_MT_TRACKING_ID: 141 if (mUsingSlotsProtocol rawEvent-value 0) { 142 // The slot is no longer in use but it retains its previous contents, 143 // which may be reused for subsequent touches. 144 slot-mInUse false; 145 } else { 146 slot-mInUse true; // 设置 mAbsMTTrackingId 147 slot-mAbsMTTrackingId rawEvent-value; 148 } 149 break; 150 case ABS_MT_PRESSURE: 151 slot-mAbsMTPressure rawEvent-value; 152 break; 153 case ABS_MT_DISTANCE: 154 slot-mAbsMTDistance rawEvent-value; 155 break; 156 case ABS_MT_TOOL_TYPE: 157 slot-mAbsMTToolType rawEvent-value; 158 slot-mHaveAbsMTToolType true; 159 break; 160 } 161 }// 如果类型是结束的话则设置 mCurrentSlot 增加1 162 } else if (rawEvent-type EV_SYN rawEvent-code SYN_MT_REPORT) { 163 // MultiTouch Sync: The driver has returned all data for *one* of the pointers. 164 mCurrentSlot 1; 165 } 166 } // 2-1)TouchInputMapper 先进行处理 process 处理是上一次的结果通过 MultiTouchMotionAccumulator.process处理了 /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp 1425 void TouchInputMapper::process(const RawEvent* rawEvent) { 1426 mCursorButtonAccumulator.process(rawEvent); 1427 mCursorScrollAccumulator.process(rawEvent); 1428 mTouchButtonAccumulator.process(rawEvent); 1429 // 如果事件是结束了的话则执行sync 1430 if (rawEvent-type EV_SYN rawEvent-code SYN_REPORT) { 1431 sync(rawEvent-when, rawEvent-readTime); 1432 } 1433 } 1435 void TouchInputMapper::sync(nsecs_t when, nsecs_t readTime) { 1436 // Push a new state. 1437 mRawStatesPending.emplace_back(); 1438 1439 RawState next mRawStatesPending.back(); 1440 next.clear(); 1441 next.when when; 1442 next.readTime readTime; 1443 1444 // Sync button state. 1445 next.buttonState 1446 mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); 1447 1448 // Sync scroll 1449 next.rawVScroll mCursorScrollAccumulator.getRelativeVWheel(); 1450 next.rawHScroll mCursorScrollAccumulator.getRelativeHWheel(); 1451 mCursorScrollAccumulator.finishSync(); 1452 // 2-1-1同步触摸事件 syncTouch 1454 syncTouch(when, next); 1455 1456 // The last RawState is the actually second to last, since we just added a new state 1457 const RawState last 1458 mRawStatesPending.size() 1 ? mCurrentRawState : mRawStatesPending.rbegin()[1]; 1459 1460 // Assign pointer ids. 1461 if (!mHavePointerIds) { 1462 assignPointerIds(last, next); 1463 } 1464 // 打开开关会打印下列的log对应的 pointerCount 手指数量 1465 #if DEBUG_RAW_EVENTS 1466 ALOGD(syncTouch: pointerCount %d - %d, touching ids 0x%08x - 0x%08x, 1467 hovering ids 0x%08x - 0x%08x, canceled ids 0x%08x, 1468 last.rawPointerData.pointerCount, next.rawPointerData.pointerCount, 1469 last.rawPointerData.touchingIdBits.value, next.rawPointerData.touchingIdBits.value, 1470 last.rawPointerData.hoveringIdBits.value, next.rawPointerData.hoveringIdBits.value, 1471 next.rawPointerData.canceledIdBits.value); 1472 #endif 1473 1474 if (!next.rawPointerData.touchingIdBits.isEmpty() 1475 !next.rawPointerData.hoveringIdBits.isEmpty() 1476 last.rawPointerData.hoveringIdBits ! next.rawPointerData.hoveringIdBits) { 1477 ALOGI(Multi-touch contains some hovering ids 0x%08x, 1478 next.rawPointerData.hoveringIdBits.value); 1479 } 1480 // 2-1-2处理触摸事件processRawTouches 1481 processRawTouches(false /*timeout*/); 1482 } input设备类型有很多种以上只是触摸设备的inputmapperMultiTouchInputMapper还有下列几种 键盘类设备KeyboardInputMapper触摸屏设备MultiTouchInputMapper或SingleTouchInputMapper鼠标类设备CursorInputMapper // 2-1-1同步触摸事件 syncTouch调用的是子类的方法 /frameworks/native/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp 最大的手指的数量为  16 个 178 #define MAX_POINTERS 16 258 void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { /// 获取的数量值为配置的值 259 size_t inCount mMultiTouchMotionAccumulator.getSlotCount(); 260 size_t outCount 0; 261 BitSet32 newPointerIdBits; 262 mHavePointerIds true; 263 // 获取到对应的slot 264 for (size_t inIndex 0; inIndex inCount; inIndex) { 265 const MultiTouchMotionAccumulator::Slot* inSlot 266 mMultiTouchMotionAccumulator.getSlot(inIndex); 267 if (!inSlot-isInUse()) { 268 continue; 269 }。。。。 // 如果超过最大18个手指则break 283 if (outCount MAX_POINTERS) { 284 #if DEBUG_POINTERS 285 ALOGD(MultiTouch device %s emitted more than maximum of %d pointers; 286 ignoring the rest., 287 getDeviceName().c_str(), MAX_POINTERS); 288 #endif 289 break; // too many fingers! 290 } 291 // 获取到 RawPointerData::Pointer设置对应的手指的参数 292 RawPointerData::Pointer outPointer outState-rawPointerData.pointers[outCount]; // 设置xy 轴的值 293 outPointer.x inSlot-getX(); 294 outPointer.y inSlot-getY(); 295 outPointer.pressure inSlot-getPressure(); 296 outPointer.touchMajor inSlot-getTouchMajor(); 297 outPointer.touchMinor inSlot-getTouchMinor(); 298 outPointer.toolMajor inSlot-getToolMajor(); 299 outPointer.toolMinor inSlot-getToolMinor(); 300 outPointer.orientation inSlot-getOrientation(); 301 outPointer.distance inSlot-getDistance(); 302 outPointer.tiltX 0; 303 outPointer.tiltY 0; 304 305 outPointer.toolType inSlot-getToolType(); 306 if (outPointer.toolType AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { 307 outPointer.toolType mTouchButtonAccumulator.getToolType(); 308 if (outPointer.toolType AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { 309 outPointer.toolType AMOTION_EVENT_TOOL_TYPE_FINGER; 310 } 311 }。。。。 318 // Assign pointer id using tracking id if available. 319 if (mHavePointerIds) { 320 int32_t trackingId inSlot-getTrackingId(); 321 int32_t id -1; 322 if (trackingId 0) { 323 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { 324 uint32_t n idBits.clearFirstMarkedBit(); 325 if (mPointerTrackingIdMap[n] trackingId) { 326 id n; 327 } 328 } 329 330 if (id 0 !mPointerIdBits.isFull()) { 331 id mPointerIdBits.markFirstUnmarkedBit(); 332 mPointerTrackingIdMap[id] trackingId; 333 } 334 } 335 if (id 0) { 336 mHavePointerIds false; 337 outState-rawPointerData.clearIdBits(); 338 newPointerIdBits.clear(); 339 } else { 340 outPointer.id id; 341 outState-rawPointerData.idToIndex[id] outCount; 342 outState-rawPointerData.markIdBit(id, isHovering); 343 newPointerIdBits.markBit(id); 344 } 345 } 346 outCount 1; 347 } 348 349 outState-rawPointerData.pointerCount outCount; 350 mPointerIdBits newPointerIdBits; 351 352 mMultiTouchMotionAccumulator.finishSync(); 353 } // 2-1-2处理触摸事件processRawTouches //将RawState的数据复制到 mCurrentRawState  1484 void TouchInputMapper::processRawTouches(bool timeout) { 1485 if (mDeviceMode DeviceMode::DISABLED) { 1486 // Drop all input if the device is disabled. 1487 cancelTouch(mCurrentRawState.when, mCurrentRawState.readTime); 1488 mCurrentCookedState.clear(); 1489 updateTouchSpots(); 1490 return; 1491 }// 遍历所有的 RawState 1497 const size_t N mRawStatesPending.size(); 1498 size_t count; 1499 for (count 0; count N; count) { 1500 const RawState next mRawStatesPending[count];1504 if (assignExternalStylusId(next, timeout)) { 1505 break; 1506 } 1507 1508 // All ready to go. 1509 clearStylusDataPendingFlags(); //将RawState的数据复制到 mCurrentRawState 1510 mCurrentRawState.copyFrom(next); 1511 if (mCurrentRawState.when mLastRawState.when) { 1512 mCurrentRawState.when mLastRawState.when; 1513 mCurrentRawState.readTime mLastRawState.readTime; 1514 }// 处理这个数据并分发cookAndDispatch 1515 cookAndDispatch(mCurrentRawState.when, mCurrentRawState.readTime); 1516 } // 处理这个数据并分发cookAndDispatch 1538 void TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t readTime) { 1539 // Always start with a clean state. 1540 mCurrentCookedState.clear(); 1541 1542 // Apply stylus buttons to current raw state. 1543 applyExternalStylusButtonState(when); 1544 1545 // Handle policy on initial down or hover events. 1546 bool initialDown mLastRawState.rawPointerData.pointerCount 0 1547 mCurrentRawState.rawPointerData.pointerCount ! 0; 1548 1549 uint32_t policyFlags 0; 1550 bool buttonsPressed mCurrentRawState.buttonState ~mLastRawState.buttonState; 1551 if (initialDown || buttonsPressed) { 1552 // If this is a touch screen, hide the pointer on an initial down. 1553 if (mDeviceMode DeviceMode::DIRECT) { 1554 getContext()-fadePointer(); 1555 } 1556 1557 if (mParameters.wake) { 1558 policyFlags | POLICY_FLAG_WAKE; 1559 } 1560 } 1564 if (consumeRawTouches(when, readTime, policyFlags)) { 1565 mCurrentRawState.rawPointerData.clear(); 1566 }// 处理pointer 数据cookPointerData 1571 cookPointerData();// 设备类型是 DIRECT 1582 if (mDeviceMode DeviceMode::POINTER) { 。。。。 1622 } else { 1623 updateTouchSpots(); 1624 1625 if (!mCurrentMotionAborted) { 1626 dispatchButtonRelease(when, readTime, policyFlags); 1627 dispatchHoverExit(when, readTime, policyFlags); // 分发tounch 事件 dispatchTouches 1628 dispatchTouches(when, readTime, policyFlags); 1629 dispatchHoverEnterAndMove(when, readTime, policyFlags); 1630 dispatchButtonPress(when, readTime, policyFlags); 1631 } // 处理pointer 数据cookPointerData 2075 void TouchInputMapper::cookPointerData() { // 设置按下手指的数量 2076 uint32_t currentPointerCount mCurrentRawState.rawPointerData.pointerCount; 2077 2078 mCurrentCookedState.cookedPointerData.clear(); 2079 mCurrentCookedState.cookedPointerData.pointerCount currentPointerCount; 2080 mCurrentCookedState.cookedPointerData.hoveringIdBits 2081 mCurrentRawState.rawPointerData.hoveringIdBits; 2082 mCurrentCookedState.cookedPointerData.touchingIdBits 2083 mCurrentRawState.rawPointerData.touchingIdBits; 2084 mCurrentCookedState.cookedPointerData.canceledIdBits 2085 mCurrentRawState.rawPointerData.canceledIdBits; 。。。。 2095 for (uint32_t i 0; i currentPointerCount; i) { 2096 const RawPointerData::Pointer in mCurrentRawState.rawPointerData.pointers[i]; 2097 2098 // Size 2099 float touchMajor, touchMinor, toolMajor, toolMinor, size; 2100 switch (mCalibration.sizeCalibration) { 2101 case Calibration::SizeCalibration::GEOMETRIC: 2102 case Calibration::SizeCalibration::DIAMETER: 2103 case Calibration::SizeCalibration::BOX: 2104 case Calibration::SizeCalibration::AREA: 。。。。 // 设置对应的touchMajor 2112 } else if (mRawPointerAxes.touchMajor.valid) { 2113 toolMajor touchMajor in.touchMajor; 2114 toolMinor touchMinor 2115 mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; 2116 size mRawPointerAxes.touchMinor.valid ? avg(in.touchMajor, in.touchMinor) 2117 : in.touchMajor; .。。。。。 // 进行仿射变换 2250 float xTransformed in.x, yTransformed in.y; 2251 mAffineTransform.applyTo(xTransformed, yTransformed); 2252 rotateAndScale(xTransformed, yTransformed); 。。。。。。// 将其数据保存到 mCurrentCookedState.cookedPointerData.pointerCoords 2302 // Write output coords. 2303 PointerCoords out mCurrentCookedState.cookedPointerData.pointerCoords[i]; 2304 out.clear(); 2305 out.setAxisValue(AMOTION_EVENT_AXIS_X, xTransformed); 2306 out.setAxisValue(AMOTION_EVENT_AXIS_Y, yTransformed); 2307 out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); 2308 out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); 2309 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); 2310 out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); 2311 out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); 2312 out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); 2313 out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); // 分发tounch 事件 dispatchTouches 1904 void TouchInputMapper::dispatchTouches(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) { 1905 BitSet32 currentIdBits mCurrentCookedState.cookedPointerData.touchingIdBits; 1906 BitSet32 lastIdBits mLastCookedState.cookedPointerData.touchingIdBits; 1907 int32_t metaState getContext()-getGlobalMetaState(); 1908 int32_t buttonState mCurrentCookedState.buttonState; 1909 1910 if (currentIdBits lastIdBits) { 。。。。。 1921 } else {// 判断是updown还是move 事件 1924 BitSet32 upIdBits(lastIdBits.value ~currentIdBits.value); 1925 BitSet32 downIdBits(currentIdBits.value ~lastIdBits.value); 1926 BitSet32 moveIdBits(lastIdBits.value currentIdBits.value); 1927 BitSet32 dispatchedIdBits(lastIdBits.value); 1928 1929 // Update last coordinates of pointers that have moved so that we observe the new 1930 // pointer positions at the same time as other pointers that have just gone up. 1931 bool moveNeeded 1932 updateMovedPointers(mCurrentCookedState.cookedPointerData.pointerProperties, 1933 mCurrentCookedState.cookedPointerData.pointerCoords, 1934 mCurrentCookedState.cookedPointerData.idToIndex, 1935 mLastCookedState.cookedPointerData.pointerProperties, 1936 mLastCookedState.cookedPointerData.pointerCoords, 1937 mLastCookedState.cookedPointerData.idToIndex, moveIdBits); 1938 if (buttonState ! mLastCookedState.buttonState) { 1939 moveNeeded true; 1940 } 1941 // 遍历所有的up 事件 1943 while (!upIdBits.isEmpty()) { // 对应的up 的按钮upId 1944 uint32_t upId upIdBits.clearFirstMarkedBit(); 1945 bool isCanceled mCurrentCookedState.cookedPointerData.canceledIdBits.hasBit(upId); 1946 if (isCanceled) { 1947 ALOGI(Canceling pointer %d for the palm event was detected., upId); 1948 }// up 的事件为 AMOTION_EVENT_ACTION_POINTER_UP事件保存再 cookedPointerData.pointerCoords走dispatchMotion 方法 1949 dispatchMotion(when, readTime, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 1950 isCanceled ? AMOTION_EVENT_FLAG_CANCELED : 0, metaState, buttonState, 0, 1951 mLastCookedState.cookedPointerData.pointerProperties, 1952 mLastCookedState.cookedPointerData.pointerCoords, 1953 mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, 1954 mOrientedXPrecision, mOrientedYPrecision, mDownTime); 1955 dispatchedIdBits.clearBit(upId); 1956 mCurrentCookedState.cookedPointerData.canceledIdBits.clearBit(upId); 1957 } // up 的事件为 AMOTION_EVENT_ACTION_POINTER_UP事件保存再 cookedPointerData.pointerCoords走dispatchMotion 方法  3601 void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags, 3602 uint32_t source, int32_t action, int32_t actionButton, 3603 int32_t flags, int32_t metaState, int32_t buttonState, 3604 int32_t edgeFlags, const PointerProperties* properties, 3605 const PointerCoords* coords, const uint32_t* idToIndex, 3606 BitSet32 idBits, int32_t changedId, float xPrecision, 3607 float yPrecision, nsecs_t downTime) { 3608 PointerCoords pointerCoords[MAX_POINTERS]; 3609 PointerProperties pointerProperties[MAX_POINTERS]; 3610 uint32_t pointerCount 0; 3611 while (!idBits.isEmpty()) { 3612 uint32_t id idBits.clearFirstMarkedBit(); 3613 uint32_t index idToIndex[id]; 3614 pointerProperties[pointerCount].copyFrom(properties[index]);// 将数据保存到pointerCoords 中 3615 pointerCoords[pointerCount].copyFrom(coords[index]); 3616 // changedId 为up 的事件 3617 if (changedId 0 id uint32_t(changedId)) { 3618 action | pointerCount AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; 3619 } 3620 3621 pointerCount 1; 3622 } 3623 3624 ALOG_ASSERT(pointerCount ! 0); 3625 // 如果是单指的话则将up事件更换为 AMOTION_EVENT_ACTION_UP 3626 if (changedId 0 pointerCount 1) { 3627 // Replace initial down and final up action. 3628 // We can compare the action without masking off the changed pointer index 3629 // because we know the index is 0. 3630 if (action AMOTION_EVENT_ACTION_POINTER_DOWN) { 3631 action AMOTION_EVENT_ACTION_DOWN; 3632 } else if (action AMOTION_EVENT_ACTION_POINTER_UP) { 3633 if ((flags AMOTION_EVENT_FLAG_CANCELED) ! 0) { 3634 action AMOTION_EVENT_ACTION_CANCEL; 3635 } else { 3636 action AMOTION_EVENT_ACTION_UP; 3637 } 3638 } else { 3639 // Cant happen. 3640 ALOG_ASSERT(false); 3641 } 3642 } 。。。。。。。 3650 const int32_t displayId getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); 3651 const int32_t deviceId getDeviceId(); 3652 std::vectorTouchVideoFrame frames getDeviceContext().getVideoFrames(); 3653 std::for_each(frames.begin(), frames.end(), 3654 [this](TouchVideoFrame frame) { frame.rotate(this-mSurfaceOrientation); });// 创建了 NotifyMotionArgs 对象pointerCoords 为对应保存的数据 3655 NotifyMotionArgs args(getContext()-getNextId(), when, readTime, deviceId, source, displayId, 3656 policyFlags, action, actionButton, flags, metaState, buttonState, 3657 MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, 3658 pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, 3659 downTime, std::move(frames)); 3660 getListener()-notifyMotion(args); 3661 } NotifyMotionArgs  重点的参数 deviceId设备id actionup还是什么其他事件 AMOTION_EVENT_ACTION_UP actionButton 为0 flags0 pointerCount手指的数量 pointerCoords保存的数据表示是 xy 坐标压力值、major等值 xPrecision, yPrecision与屏幕方向有关 xCursorPosition, yCursorPosition都是无效的 notifymotion 通知到 InputDispatcher /frameworks/native/services/inputflinger/reader/mapper/TouchInputMapper.cpp 3601 void TouchInputMapper::dispatchMotion(nsecs_t when, nsecs_t readTime, uint32_t policyFlags, 3602 uint32_t source, int32_t action, int32_t actionButton, 3603 int32_t flags, int32_t metaState, int32_t buttonState, 3604 int32_t edgeFlags, const PointerProperties* properties, 3605 const PointerCoords* coords, const uint32_t* idToIndex, 3606 BitSet32 idBits, int32_t changedId, float xPrecision, 3607 float yPrecision, nsecs_t downTime) { 3608 PointerCoords pointerCoords[MAX_POINTERS]; 3609 PointerProperties pointerProperties[MAX_POINTERS]; 3610 uint32_t pointerCount 0; 3611 while (!idBits.isEmpty()) { 3612 uint32_t id idBits.clearFirstMarkedBit(); 3613 uint32_t index idToIndex[id]; 3614 pointerProperties[pointerCount].copyFrom(properties[index]); 3615 pointerCoords[pointerCount].copyFrom(coords[index]); 3616 3617 if (changedId 0 id uint32_t(changedId)) { 3618 action | pointerCount AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; 3619 } 3620 3621 pointerCount 1; 3622 } 3623 3624 ALOG_ASSERT(pointerCount ! 0); 3625 // 如果是单指的话则会将AMOTION_EVENT_ACTION_POINTER_UP设置为 AMOTION_EVENT_ACTION_UP 3626 if (changedId 0 pointerCount 1) { 3627 // Replace initial down and final up action. 3628 // We can compare the action without masking off the changed pointer index 3629 // because we know the index is 0. 3630 if (action AMOTION_EVENT_ACTION_POINTER_DOWN) { 3631 action AMOTION_EVENT_ACTION_DOWN; 3632 } else if (action AMOTION_EVENT_ACTION_POINTER_UP) { 3633 if ((flags AMOTION_EVENT_FLAG_CANCELED) ! 0) { 3634 action AMOTION_EVENT_ACTION_CANCEL; 3635 } else { 3636 action AMOTION_EVENT_ACTION_UP; 3637 } 3638 } else { 3639 // Cant happen. 3640 ALOG_ASSERT(false); 3641 } 3642 } 3643 float xCursorPosition AMOTION_EVENT_INVALID_CURSOR_POSITION; 3644 float yCursorPosition AMOTION_EVENT_INVALID_CURSOR_POSITION; 3645 if (mDeviceMode DeviceMode::POINTER) { 3646 auto [x, y] getMouseCursorPosition(); 3647 xCursorPosition x; 3648 yCursorPosition y; 3649 } 3650 const int32_t displayId getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); 3651 const int32_t deviceId getDeviceId(); 3652 std::vectorTouchVideoFrame frames getDeviceContext().getVideoFrames(); 3653 std::for_each(frames.begin(), frames.end(), 3654 [this](TouchVideoFrame frame) { frame.rotate(this-mSurfaceOrientation); });// 将所有的参数封装为 NotifyMotionArgs 3655 NotifyMotionArgs args(getContext()-getNextId(), when, readTime, deviceId, source, displayId, 3656 policyFlags, action, actionButton, flags, metaState, buttonState, 3657 MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties, 3658 pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition, 3659 downTime, std::move(frames));// getListener 去通知到观察者 3660 getListener()-notifyMotion(args); 3661 } getListener 的实现为 /frameworks/native/services/inputflinger/reader/mapper/InputMapper.h TouchInputMapper 类继承了 InputMapper // 这里获取到context通过 mDeviceContext.getContext() 49 inline InputReaderContext* getContext() { return mDeviceContext.getContext(); }// 通过ceontext 获取到 Listener 51 inline InputListenerInterface* getListener() { return getContext()-getListener(); } mDeviceContext 是在初始化  传入的 /frameworks/native/services/inputflinger/reader/InputDevice.cpp 143 void InputDevice::addEventHubDevice(int32_t eventHubId, bool populateMappers) { 144 if (mDevices.find(eventHubId) ! mDevices.end()) { 145 return; 146 } 147 std::unique_ptrInputDeviceContext contextPtr(new InputDeviceContext(*this, eventHubId));。。。。 204 // Touchscreens and touchpad devices. 205 if (classes.test(InputDeviceClass::TOUCH_MT)) {// contextPtr 是 InputDeviceContext 对象 206 mappers.push_back(std::make_uniqueMultiTouchInputMapper(*contextPtr)); 所以 mDeviceContext 是 InputDeviceContext再调用其 getContext 方法 /frameworks/native/services/inputflinger/reader/include/InputDevice.h 239 class InputDeviceContext { 240 public: 241 InputDeviceContext(InputDevice device, int32_t eventHubId); 242 ~InputDeviceContext(); 243 244 inline InputReaderContext* getContext() { return mContext; } 600 InputDeviceContext::InputDeviceContext(InputDevice device, int32_t eventHubId) 601 : mDevice(device),// 为构造函数中传入的即通过 InputDevice.getContext 获取 602 mContext(device.getContext()), 603 mEventHub(device.getContext()-getEventHub()), 604 mId(eventHubId), // 为构造函数中传入的即通过 InputDevice.getContext 获取 也是再 InputDevice 中传入的 44 class InputDevice { 45 public: 46 InputDevice(InputReaderContext* context, int32_t id, int32_t generation, 47 const InputDeviceIdentifier identifier); 48 ~InputDevice(); 49 50 inline InputReaderContext* getContext() { return mContext; } mContext 为内部的类为 ContextImpl /frameworks/native/services/inputflinger/reader/include/InputReader.h 124 class ContextImpl : public InputReaderContext { 125 InputReader* mReader; 126 IdGenerator mIdGenerator; 127 128 public: 129 explicit ContextImpl(InputReader* reader); 130 // lock is already held by the input loop 131 void updateGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override; 132 int32_t getGlobalMetaState() NO_THREAD_SAFETY_ANALYSIS override; 133 void disableVirtualKeysUntil(nsecs_t time) REQUIRES(mReader-mLock) override; 134 bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) 135 REQUIRES(mReader-mLock) override; 136 void fadePointer() REQUIRES(mReader-mLock) override; 137 std::shared_ptrPointerControllerInterface getPointerController(int32_t deviceId) 138 REQUIRES(mReader-mLock) override; 139 void requestTimeoutAtTime(nsecs_t when) REQUIRES(mReader-mLock) override; 140 int32_t bumpGeneration() NO_THREAD_SAFETY_ANALYSIS override; 141 void getExternalStylusDevices(std::vectorInputDeviceInfo outDevices) 142 REQUIRES(mReader-mLock) override; 143 void dispatchExternalStylusState(const StylusState outState) 144 REQUIRES(mReader-mLock) override; 145 InputReaderPolicyInterface* getPolicy() REQUIRES(mReader-mLock) override; 146 InputListenerInterface* getListener() REQUIRES(mReader-mLock) override; 147 EventHubInterface* getEventHub() REQUIRES(mReader-mLock) override; 148 int32_t getNextId() NO_THREAD_SAFETY_ANALYSIS override; 149 void updateLedMetaState(int32_t metaState) REQUIRES(mReader-mLock) override; 150 int32_t getLedMetaState() REQUIRES(mReader-mLock) REQUIRES(mLock) override; 151 } mContext; 综上 InputReaderContext* getContext() 返回的对象是  InputReader 的 ContextImpl  接着调用其 listener 的方法 /frameworks/native/services/inputflinger/reader/InputReader.cpp 948 InputListenerInterface* InputReader::ContextImpl::getListener() { // 获取到的是 对象 949 return mReader-mQueuedListener.get(); 950 } 43 InputReader::InputReader(std::shared_ptrEventHubInterface eventHub, 44 const spInputReaderPolicyInterface policy, // listener 传入的参数是 InputDispatcher 45 const spInputListenerInterface listener) 46 : mContext(this), 47 mEventHub(eventHub), 48 mPolicy(policy), 49 mGlobalMetaState(0), 50 mLedMetaState(AMETA_NUM_LOCK_ON), 51 mGeneration(1), 52 mNextInputDeviceId(END_RESERVED_ID), 53 mDisableVirtualKeysTimeout(LLONG_MIN), 54 mNextTimeout(LLONG_MAX), 55 mConfigurationChangesToRefresh(0) { 56 mQueuedListener new QueuedInputListener(listener); 所以是调用到 QueuedInputListener 的方法 notifyMotion /frameworks/native/services/inputflinger/InputListener.cpp 315 QueuedInputListener::QueuedInputListener(const spInputListenerInterface innerListener) : 316 mInnerListener(innerListener) { 317 }337 void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { 338 traceEvent(__func__, args-id);// 创建 NotifyMotionArgs 对象包装 args将其保存到参数队列中 339 mArgsQueue.push_back(new NotifyMotionArgs(*args)); 340 } // 最后需要调用flush去统一派发 367 void QueuedInputListener::flush() { 368 size_t count mArgsQueue.size(); 369 for (size_t i 0; i count; i) { 370 NotifyArgs* args mArgsQueue[i]; 371 args-notify(mInnerListener); 372 delete args; 373 } 374 mArgsQueue.clear(); 375 } // 然后调用观察者 InputDispatcher 去通知触摸事件 notifyMotion 191 void NotifyMotionArgs::notify(const spInputListenerInterface listener) const { 192 listener-notifyMotion(this); 193 } // 3观察者队列去flush处理全部的事件flush 调用观察者 InputDispatcher 去通知触摸事件 notifyMotion /frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp 3817 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { 3818 #if DEBUG_INBOUND_EVENT_DETAILS// 会打印对应的log 3819 ALOGD(notifyMotion - id% PRIx32 eventTime% PRId64 , deviceId%d, source0x%x, 3820 displayId% PRId32 , policyFlags0x%x, 3821 action0x%x, actionButton0x%x, flags0x%x, metaState0x%x, buttonState0x%x, 3822 edgeFlags0x%x, xPrecision%f, yPrecision%f, xCursorPosition%f, 3823 yCursorPosition%f, downTime% PRId64, 3824 args-id, args-eventTime, args-deviceId, args-source, args-displayId, 3825 args-policyFlags, args-action, args-actionButton, args-flags, args-metaState, 3826 args-buttonState, args-edgeFlags, args-xPrecision, args-yPrecision, 3827 args-xCursorPosition, args-yCursorPosition, args-downTime); 3828 for (uint32_t i 0; i args-pointerCount; i) { 3829 ALOGD( Pointer %d: id%d, toolType%d, 3830 x%f, y%f, pressure%f, size%f, 3831 touchMajor%f, touchMinor%f, toolMajor%f, toolMinor%f, 3832 orientation%f, 3833 i, args-pointerProperties[i].id, args-pointerProperties[i].toolType, 3834 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), 3835 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), 3836 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), 3837 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), 3838 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), 3839 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), 3840 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), 3841 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), 3842 args-pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); 3843 }。。。。。 3885 // Just enqueue a new motion event.// 将args 封装为 MotionEntry 对象 3886 std::unique_ptrMotionEntry newEntry 3887 std::make_uniqueMotionEntry(args-id, args-eventTime, args-deviceId, 3888 args-source, args-displayId, policyFlags, 3889 args-action, args-actionButton, args-flags, 3890 args-metaState, args-buttonState, 3891 args-classification, args-edgeFlags, 3892 args-xPrecision, args-yPrecision, 3893 args-xCursorPosition, args-yCursorPosition, 3894 args-downTime, args-pointerCount, 3895 args-pointerProperties, args-pointerCoords, 0, 0); 3896 // 将其假如到处理的队列然后唤醒 inputdispatcher 线程 3897 needWake enqueueInboundEventLocked(std::move(newEntry)); 3898 mLock.unlock(); 3899 } // release lock 3900 3901 if (needWake) { 3902 mLooper-wake(); 3903 } 3904 }
http://www.w-s-a.com/news/644743/

相关文章:

  • wordpress情侣源码西安网站快速优化
  • 昆明网站建设高端定制100种班服设计图
  • 网站开发程序说明html网页制作接单
  • 企业网站货物查询怎么做制作文件的软件
  • 怎么做网站的防盗链北京门户企业网站建设
  • 网站推广的主流方法淘客网站 源码
  • 网站海外推广怎么做多用户商城系统源码教程
  • 猎头做单网站网站创建费用
  • 住房和城乡建设网站 上海自己做网站还是公众号
  • 投票网站怎么制作电商网站模板html
  • 攀枝花移动网站建设抖音广告投放平台
  • 什么是网站设计第一装修网
  • 公司网站建设一条织梦门户网站源码
  • 网站改版中su域名注册
  • 做网站有没有前途济南产品网站建设外包
  • 网站备案咨询做静态网站多少钱
  • 软件开发和网站建设一样吗太原今天最新通知
  • 网站推广如何做的表白制作网站
  • 网站风格分析免费织梦网站源码
  • 大连手机自适应网站建设织梦做音乐网站
  • 烟台网站建设优化网页设计师证
  • 手机微网站建设多少钱个人网站 wordpress
  • 做外贸是不是必须有网站wordpress网络图片
  • 赣县企业网站建设用dw做网站的基本步骤
  • 辽源网站建设微信小程序公众平台
  • 多媒体网站设计开发是指什么常宁网站建设
  • 淄博网站推广优化17岁在线观看免费高清完整版
  • 企业形象网站开发业务范畴wordpress最好最全的教程
  • 企业网站的建立意义网站首页制作网站
  • 网站制作过程内容深圳最好的活动策划公司